[
  {
    "path": ".gitignore",
    "content": "/output\n/Makefile\n/brpc\n/_build\n/build\n/.vscode\n*.pyc\n.DS_Store\n"
  },
  {
    "path": "CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 2.8.10)\nproject(dmkit C CXX)\n\nexecute_process(\n    COMMAND bash -c \"find ${CMAKE_SOURCE_DIR}/brpc -type d -regex \\\".*output/include$\\\" | xargs dirname | tr -d '\\n'\"\n    OUTPUT_VARIABLE OUTPUT_PATH\n)\n\nset(CMAKE_PREFIX_PATH ${OUTPUT_PATH})\n\ninclude(FindThreads)\ninclude(FindProtobuf)\nprotobuf_generate_cpp(PROTO_SRC PROTO_HEADER proto/http.proto)\n# include PROTO_HEADER\ninclude_directories(${CMAKE_CURRENT_BINARY_DIR})\n\nfind_path(BRPC_INCLUDE_PATH NAMES brpc/server.h)\nfind_library(BRPC_LIB NAMES libbrpc.a brpc)\nif((NOT BRPC_INCLUDE_PATH) OR (NOT BRPC_LIB))\n    message(FATAL_ERROR \"Fail to find brpc\")\nendif()\ninclude_directories(${BRPC_INCLUDE_PATH})\n\nfind_path(GFLAGS_INCLUDE_PATH gflags/gflags.h)\nfind_library(GFLAGS_LIBRARY NAMES gflags libgflags)\nif((NOT GFLAGS_INCLUDE_PATH) OR (NOT GFLAGS_LIBRARY))\n    message(FATAL_ERROR \"Fail to find gflags\")\nendif()\ninclude_directories(${GFLAGS_INCLUDE_PATH})\n\nexecute_process(\n    COMMAND bash -c \"grep \\\"namespace [_A-Za-z0-9]\\\\+ {\\\" ${GFLAGS_INCLUDE_PATH}/gflags/gflags_declare.h | head -1 | awk '{print $2}' | tr -d '\\n'\"\n    OUTPUT_VARIABLE GFLAGS_NS\n)\nif(${GFLAGS_NS} STREQUAL \"GFLAGS_NAMESPACE\")\n    execute_process(\n        COMMAND bash -c \"grep \\\"#define GFLAGS_NAMESPACE [_A-Za-z0-9]\\\\+\\\" ${GFLAGS_INCLUDE_PATH}/gflags/gflags_declare.h | head -1 | awk '{print $3}' | tr -d '\\n'\"\n        OUTPUT_VARIABLE GFLAGS_NS\n    )\nendif()\n\nif(CMAKE_SYSTEM_NAME STREQUAL \"Darwin\")\n    include(CheckFunctionExists)\n    CHECK_FUNCTION_EXISTS(clock_gettime HAVE_CLOCK_GETTIME)\n    if(NOT HAVE_CLOCK_GETTIME)\n        set(DEFINE_CLOCK_GETTIME \"-DNO_CLOCK_GETTIME_IN_MAC\")\n    endif()\nendif()\n\nset(CMAKE_CPP_FLAGS \"${DEFINE_CLOCK_GETTIME} ${CMAKE_CPP_FLAGS} -DGFLAGS_NS=${GFLAGS_NS}\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CPP_FLAGS} -DNDEBUG -O2 -D__const__= -pipe -W -Wall -Wno-unused-parameter -fPIC -fno-omit-frame-pointer\")\n\nif(CMAKE_VERSION VERSION_LESS \"3.1.3\")\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"GNU\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n    endif()\n    if(CMAKE_CXX_COMPILER_ID STREQUAL \"Clang\")\n        set(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++11\")\n    endif()\nelse()\n    set(CMAKE_CXX_STANDARD 11)\n    set(CMAKE_CXX_STANDARD_REQUIRED ON)\nendif()\n\nfind_path(LEVELDB_INCLUDE_PATH NAMES leveldb/db.h)\nfind_library(LEVELDB_LIB NAMES leveldb)\nif ((NOT LEVELDB_INCLUDE_PATH) OR (NOT LEVELDB_LIB))\n    message(FATAL_ERROR \"Fail to find leveldb\")\nendif()\ninclude_directories(${LEVELDB_INCLUDE_PATH})\n\nif(CMAKE_SYSTEM_NAME STREQUAL \"Darwin\")\n    set(OPENSSL_ROOT_DIR\n        \"/usr/local/opt/openssl\"    # Homebrew installed OpenSSL\n        )\nendif()\ninclude(FindOpenSSL)\n\nfind_library(CURL_LIB NAMES curl)\nif (NOT CURL_LIB)\n    message(FATAL_ERROR \"Fail to find curl\")\nendif()\n\nset(DYNAMIC_LIB\n    ${CMAKE_THREAD_LIBS_INIT}\n    ${GFLAGS_LIBRARY}\n    ${PROTOBUF_LIBRARIES}\n    ${LEVELDB_LIB}\n    ${OPENSSL_LIBRARIES}\n    ${OPENSSL_CRYPTO_LIBRARY}\n    ${CURL_LIB}\n    dl\n    )\n\nif(CMAKE_SYSTEM_NAME STREQUAL \"Darwin\")\n    set(DYNAMIC_LIB ${DYNAMIC_LIB}\n        pthread\n        \"-framework CoreFoundation\"\n        \"-framework CoreGraphics\"\n        \"-framework CoreData\"\n        \"-framework CoreText\"\n        \"-framework Security\"\n        \"-framework Foundation\"\n        \"-Wl,-U,_MallocExtension_ReleaseFreeMemory\"\n        \"-Wl,-U,_ProfilerStart\"\n        \"-Wl,-U,_ProfilerStop\"\n        \"-Wl,-U,_RegisterThriftProtocol\")\nendif()\n\nfile(GLOB DMKIT_SRC\n    \"src/*.cpp\"\n    \"src/*/*.cpp\"\n    )\n\ninclude_directories(\n    ${CMAKE_SOURCE_DIR}/src\n    )\n\nadd_executable(dmkit ${DMKIT_SRC} ${PROTO_SRC} ${PROTO_HEADER})\n\ntarget_link_libraries(dmkit ${BRPC_LIB} ${DYNAMIC_LIB})\n\nadd_custom_command(\n    TARGET dmkit POST_BUILD\n    COMMAND ${CMAKE_COMMAND} -E copy_directory\n    ${CMAKE_SOURCE_DIR}/conf\n    ${CMAKE_BINARY_DIR}/conf\n    )\n"
  },
  {
    "path": "Dockerfile",
    "content": "FROM ubuntu:18.04\n\nWORKDIR /unit-dmkit\n\nCOPY . /unit-dmkit\n\nRUN apt-get update && apt-get install -y --no-install-recommends sudo cmake wget vim curl ca-certificates\n\nRUN update-ca-certificates\n\nRUN sh deps.sh ubuntu\n\nRUN rm -rf _build && mkdir _build && cd _build && cmake .. && make -j8\n\nEXPOSE 8010\n\n"
  },
  {
    "path": "LICENSE",
    "content": "\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"[]\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright [yyyy] [name of copyright owner]\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   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."
  },
  {
    "path": "NOTICE",
    "content": "Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   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."
  },
  {
    "path": "README.md",
    "content": "# DMKit\n\nDMKit作为UNIT的开源对话管理模块，可以无缝对接UNIT的理解能力，并赋予开发者多状态的复杂对话流程管理能力，还可以低成本对接外部知识库，迅速丰富话术信息量。\n\n## 快速开始\n\n### 编译DMKit\n\nDMKit基于[brpc](https://github.com/brpc/brpc)开发并提供HTTP服务，支持MacOS，Ubuntu，Centos等系统环境，推荐使用Ubuntu 16.04或CentOS 7。在编译DMKit之前，需要先安装依赖并下载编译brpc：\n\n```bash\nsh deps.sh [OS]\n```\n\n其中[OS]参数指定系统类型用于安装对应系统依赖，支持取值包括ubuntu、mac、centos。如果已手动安装依赖，则传入none。\n\n使用cmake编译DMKit：\n\n```bash\nmkdir _build && cd _build && cmake .. && make\n```\n\n### 运行示例技能\n\nDMKit提供了示例场景技能，在运行示例技能之前，需要在UNIT平台配置实现技能的理解能力：[示例场景](docs/demo_skills.md)\n\n根据UNIT平台创建的skill id修改编译产出_build目录下的conf/app/products.json文件，在其中配置所创建skill id与对应场景DMKit配置文件。例如，查询流量及续订场景，在UNIT平台创建skill id为12345，则对应的配置文件内容应为：\n\n```JSON\n{\n    \"default\": {\n        \"12345\": {\n            \"score\": 1,\n            \"conf_path\": \"conf/app/demo/cellular_data.json\"\n        }\n    }\n}\n```\n\n在_build目录下运行DMKit：\n\n```bash\n./dmkit\n```\n\n可以通过tools目录下的bot_emulator.py程序模拟与技能进行交互，使用方法为：\n\n```bash\npython bot_emulator.py [skill id] [access token]\n```\n\n### 更多文档\n\n* [DMKit快速上手](docs/tutorial.md)\n* [可视化配置工具](docs/visual_tool.md)\n* [常见问题](docs/faq.md)\n\n### 多语言支持\n* PHP：[PHP版本官方代码库](https://github.com/baidu/dm-kit-php)\n\n## 如何贡献\n\n* 提交issue可以是新需求也可以是bug，也可以是对某一个问题的讨论。\n* 对于issues中的问题欢迎贡献并发起pull request。\n\n## 讨论\n\n* 提issue发起问题讨论，如果是问题选择类型为问题即可。\n* 欢迎加入UNIT QQ群（584835350）交流讨论。\n"
  },
  {
    "path": "conf/app/bot_tokens.json",
    "content": "{\n    \"1234\": {\n        \"api_key\": \"\",\n        \"secret_key\": \"\"  \n    }\n}\n"
  },
  {
    "path": "conf/app/demo/book_hotel.json",
    "content": "[\n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"请问您要预订哪里的酒店\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"001\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"{%location%}附近的酒店有{%hotel_option%}，请问你要预订哪一个？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"location\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_location\"\n      }, \n      {\n        \"name\": \"hotel_option\", \n        \"type\": \"func_val\", \n        \"value\": \"service_http_get:hotel_service,/hotel/search?location={%location%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\", \n        \"user_location\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"{%location%}附近的酒店有{%hotel_option%}，请问你要预订哪一个？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"location\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_location\"\n      }, \n      {\n        \"name\": \"hotel_option\", \n        \"type\": \"func_val\", \n        \"value\": \"service_http_get:hotel_service,/hotel/search?location={%location%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\", \n        \"user_location\"\n      ], \n      \"state\": \"001\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您选择了{%time%}{%hotel%}的{%room_type%}，是否确认预订？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"hotel\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_hotel\"\n      }, \n      {\n        \"name\": \"room_type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_room_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\", \n        \"user_hotel\"\n      ], \n      \"state\": \"001\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您选择了{%time%}{%hotel%}的{%room_type%}，是否确认预订？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"hotel\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_hotel\"\n      }, \n      {\n        \"name\": \"room_type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_room_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\", \n        \"user_hotel\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"已为您预订{%time%}{%hotel%}的{%room_type%}\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"hotel\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_hotel\"\n      }, \n      {\n        \"name\": \"room_type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_room_type\"\n      }, \n      {\n        \"name\": \"hotel_option\", \n        \"type\": \"func_val\", \n        \"value\": \"service_http_get:hotel_service,/hotel/book?time={%time%}&hotel={%hotel%}&room_type={%room_type%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"002\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"请告诉我您的新需求\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"005\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"002\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您选择了{%time%}{%hotel%}的{%room_type%}，是否确认预订？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"hotel\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_hotel\"\n      }, \n      {\n        \"name\": \"room_type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_room_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_HOTEL\", \n      \"slots\": [\n        \"user_time\", \n        \"user_room_type\", \n        \"user_location\", \n        \"user_hotel\"\n      ], \n      \"state\": \"\"\n    }\n  }\n]\n"
  },
  {
    "path": "conf/app/demo/book_hotel.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<mxGraphModel dx=\"1640\" dy=\"390\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"850\" pageHeight=\"1100\" background=\"#ffffff\" math=\"0\" shadow=\"0\"><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/><mxCell id=\"12\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"2\" target=\"3\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"2\" value=\"INTENT:INTENT_BOOK_HOTEL&lt;br&gt;SLOT:user_time,user_room_type&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"140\" y=\"250\" width=\"260\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"13\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"3\" target=\"5\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"21\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=1;exitY=0.5;entryX=0;entryY=0.5;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"3\" target=\"4\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"3\" value=\"BOT:请问您要预订哪里的酒店\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"140\" y=\"360\" width=\"260\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"20\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"4\" target=\"8\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"4\" value=\"INTENT:INTENT_BOOK_HOTEL&lt;br&gt;SLOT:user_time,user_room_type,user_location&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"560\" y=\"360\" width=\"260\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"14\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"5\" target=\"7\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"5\" value=\"INTENT:INTENT_BOOK_HOTEL&lt;br&gt;SLOT:user_time,user_room_type,user_hotel&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"140\" y=\"470\" width=\"260\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"16\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"6\" target=\"9\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"6\" value=\"INTENT:INTENT_YES&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"140\" y=\"710\" width=\"260\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"15\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"7\" target=\"6\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"17\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0;exitY=0.5;entryX=1;entryY=0.5;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"7\" target=\"10\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"7\" value=\"PARAM:slot_val:time=user_time&lt;br&gt;PARAM:slot_val:hotel=user_hotel&lt;br&gt;PARAM:slot_val:room_type=user_room_type&lt;br&gt;BOT:您选择了{%time%}{%hotel%}的{%room_type%}，是否确认预订？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"65\" y=\"590\" width=\"410\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"8\" value=\"&lt;br&gt;PARAM:slot_val:location=user_location&lt;br&gt;PARAM:func_val:hotel_option=&lt;span&gt;service_http_get:hotel_service,/hotel/search?location={%location%}&lt;/span&gt;&lt;br&gt;BOT:{%location%}附近的酒店有{%hotel_option%}，请问你要预订哪一个？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"440\" y=\"470\" width=\"500\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"9\" value=\"PARAM:slot_val:time=user_time&lt;br&gt;PARAM:slot_val:hotel=user_hotel&lt;br&gt;PARAM:slot_val:room_type=user_room_type&lt;br&gt;PARAM:func_val:hotel_option=service_http_get:hotel_service,/hotel/book?time={%time%}&amp;amp;hotel={%hotel%}&amp;amp;room_type={%room_type%}&lt;br&gt;BOT:已为您预订{%time%}{%hotel%}的{%room_type%}\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"-80\" y=\"830\" width=\"700\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"18\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=0;entryX=0.5;entryY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"10\" target=\"11\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"10\" value=\"INTENT:INTENT_NO&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"-170\" y=\"590\" width=\"190\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"11\" value=\"BOT:请告诉我您的新需求\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"-170\" y=\"470\" width=\"190\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"22\" value=\"\" style=\"endArrow=classic;html=1;strokeWidth=2;entryX=0;entryY=0.5;\" parent=\"1\" target=\"5\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"100\" y=\"240\" as=\"sourcePoint\"/><mxPoint x=\"490\" y=\"335\" as=\"targetPoint\"/><Array as=\"points\"><mxPoint x=\"100\" y=\"510\"/></Array></mxGeometry></mxCell><mxCell id=\"24\" value=\"\" style=\"endArrow=classic;html=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" target=\"4\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"690\" y=\"270\" as=\"sourcePoint\"/><mxPoint x=\"750\" y=\"260\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"25\" value=\"\" style=\"endArrow=classic;html=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" target=\"2\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"270\" y=\"190\" as=\"sourcePoint\"/><mxPoint x=\"300\" y=\"210\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"28\" value=\"INTENT:INTENT_BOOK_HOTEL&lt;br&gt;SLOT:user_time,user_room_type,user_location,user_hotel&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"530\" y=\"590\" width=\"330\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"29\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;entryX=1;entryY=0.5;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" edge=\"1\" parent=\"1\" target=\"28\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"930\" y=\"630\" as=\"sourcePoint\"/><mxPoint x=\"740\" y=\"740\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"30\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0;exitY=0.5;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=1;entryY=0.5;\" edge=\"1\" parent=\"1\" source=\"28\" target=\"7\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"290\" y=\"570\" as=\"sourcePoint\"/><mxPoint x=\"540\" y=\"670\" as=\"targetPoint\"/></mxGeometry></mxCell></root></mxGraphModel>"
  },
  {
    "path": "conf/app/demo/cellular_data.json",
    "content": "[\n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您想查询几月份的流量？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"001\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_CHECK_DATA_USAGE\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [\n          {\n            \"type\": \"ge\", \n            \"value\": \"{%left%},1\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您的省内流量2GB,已用流量为{%usage%}GB；剩余流量为{%left%}G，全国流量包1GB，已用流量为1GB，剩余流量为0GB\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }, \n      {\n        \"assertion\": [\n          {\n            \"type\": \"gt\", \n            \"value\": \"1,{%left%}\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您的省内流量2GB，已用流量为{%usage%}GB，剩余流量为{%left%}G；全国流量包1GB，已用流量为1GB，剩余流量为0GB。发现您的流量余额已经不足了，您是否需要续订流量包呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"usage\", \n        \"type\": \"func_val\", \n        \"value\": \"demo_get_cellular_data_usage:{%time%}\"\n      }, \n      {\n        \"name\": \"left\", \n        \"type\": \"func_val\", \n        \"value\": \"demo_get_cellular_data_left:{%time%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_CHECK_DATA_USAGE\", \n      \"slots\": [\n        \"user_time\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [\n          {\n            \"type\": \"ge\", \n            \"value\": \"{%left%},1\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您的省内流量2GB,已用流量为{%usage%}GB；剩余流量为{%left%}G，全国流量包1GB，已用流量为1GB，剩余流量为0GB\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }, \n      {\n        \"assertion\": [\n          {\n            \"type\": \"gt\", \n            \"value\": \"1,{%left%}\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您的省内流量2GB，已用流量为{%usage%}GB，剩余流量为{%left%}G；全国流量包1GB，已用流量为1GB，剩余流量为0GB。发现您的流量余额已经不足了，您是否需要续订流量包呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"time\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_time\"\n      }, \n      {\n        \"name\": \"usage\", \n        \"type\": \"func_val\", \n        \"value\": \"demo_get_cellular_data_usage:{%time%}\"\n      }, \n      {\n        \"name\": \"left\", \n        \"type\": \"func_val\", \n        \"value\": \"demo_get_cellular_data_left:{%time%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_CHECK_DATA_USAGE\", \n      \"slots\": [\n        \"user_time\"\n      ], \n      \"state\": \"001\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"王女士您好，我们有省内，全国，夜间三种流量包，您是要续订什么流量包？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"003\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问还有什么可以帮助您的吗\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"007\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"003\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的，{%type%}有如下选择：{%options%}。请问您想续订哪种？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"005\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_package_type\"\n      }, \n      {\n        \"name\": \"options\", \n        \"type\": \"func_val\", \n        \"value\": \"demo_get_package_options:{%type%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_DATA_PACKAGE\", \n      \"slots\": [\n        \"user_package_type\"\n      ], \n      \"state\": \"004\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，您是想续订{%name%}的{%type%}吗？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"006\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_package_type\"\n      }, \n      {\n        \"name\": \"name\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_package_name\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_DATA_PACKAGE\", \n      \"slots\": [\n        \"user_package_type\", \n        \"user_package_name\"\n      ], \n      \"state\": \"005\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问还有什么可以帮助您的吗\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"007\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"006\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"王女士您好，我们有省内，全国，夜间三种流量包，您是要续订什么流量包？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_DATA_PACKAGE\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"王女士您好，我们有省内，全国，夜间三种流量包，您是要续订什么流量包？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_BOOK_DATA_PACKAGE\", \n      \"slots\": [], \n      \"state\": \"003\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的，很高兴为您服务\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"008\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"007\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"{%dmkit_param_last_tts%}\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"{%state%}\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"state\", \n        \"type\": \"session_state\", \n        \"value\": \"\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_REPEAT\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"嗯，您说？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"009\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"dmkit_param_context_state\", \n        \"type\": \"session_state\", \n        \"value\": \"\"\n      }, \n      {\n        \"name\": \"dmkit_param_context_tts\", \n        \"type\": \"string\", \n        \"value\": \"{%dmkit_param_last_tts%}\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_WAIT\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"{%dmkit_param_context_tts%}\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"{%dmkit_param_context_state%}\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_CONTINUE\", \n      \"slots\": [], \n      \"state\": \"009\"\n    }\n  }\n]\n"
  },
  {
    "path": "conf/app/demo/cellular_data.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<mxGraphModel dx=\"790\" dy=\"376\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"850\" pageHeight=\"1100\" background=\"#ffffff\" math=\"0\" shadow=\"0\"><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/><mxCell id=\"4\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"2\" target=\"7\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"310\" y=\"220\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"47\" value=\"\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"2\" target=\"7\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"2\" value=\"INTENT:&lt;span&gt;INTENT_CHECK_DATA_USAGE&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"150\" y=\"80\" width=\"320\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"6\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"7\" target=\"5\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"310\" y=\"280\" as=\"sourcePoint\"/></mxGeometry></mxCell><mxCell id=\"9\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"5\" target=\"8\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"5\" value=\"INTENT:INTENT_CHECK_DATA_USAGE&lt;br&gt;SLOT:&lt;span&gt;user_time&lt;/span&gt;&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"150\" y=\"370\" width=\"320\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"7\" value=\"BOT:您想查询几月份的流量？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"150\" y=\"220\" width=\"320\" height=\"100\" as=\"geometry\"/></mxCell><mxCell id=\"10\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"8\" target=\"11\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"100\" y=\"690\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"39\" value=\"&lt;span&gt;ge:{%&lt;/span&gt;&lt;span&gt;left&lt;/span&gt;&lt;span&gt;%},1&lt;/span&gt;\" style=\"text;html=1;resizable=0;points=[];align=center;verticalAlign=middle;labelBackgroundColor=#ffffff;\" parent=\"10\" vertex=\"1\" connectable=\"0\"><mxGeometry x=\"0.1\" y=\"2\" relative=\"1\" as=\"geometry\"><mxPoint as=\"offset\"/></mxGeometry></mxCell><mxCell id=\"13\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"8\" target=\"12\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"40\" value=\"gt:1,{%left%}\" style=\"text;html=1;resizable=0;points=[];align=center;verticalAlign=middle;labelBackgroundColor=#ffffff;\" parent=\"13\" vertex=\"1\" connectable=\"0\"><mxGeometry x=\"-0.037\" y=\"2\" relative=\"1\" as=\"geometry\"><mxPoint as=\"offset\"/></mxGeometry></mxCell><mxCell id=\"8\" value=\"PARAM:slot_val:time=&lt;span&gt;user_time&lt;/span&gt;&lt;br&gt;PARAM:func_val:usage=&lt;span&gt;demo_get_cellular_data_usage&lt;/span&gt;&lt;span&gt;:{%time%}&lt;br&gt;&lt;/span&gt;PARAM:func_val:left=demo_get_cellular_data_left:{%time%}&lt;br&gt;\" style=\"rhombus;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"100\" y=\"510\" width=\"420\" height=\"100\" as=\"geometry\"/></mxCell><mxCell id=\"11\" value=\"BOT:您的省内流量2GB,已用流量为{%usage%}GB；剩余流量为{%left%}G，全国流量包1GB，已用流量为1GB，剩余流量为0GB&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"20\" y=\"700\" width=\"200\" height=\"100\" as=\"geometry\"/></mxCell><mxCell id=\"14\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.25;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"12\" target=\"16\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"260\" y=\"930\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"15\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.75;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"12\" target=\"17\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"700\" y=\"920\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"58\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"12\" target=\"50\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><Array as=\"points\"><mxPoint x=\"490\" y=\"890\"/><mxPoint x=\"574\" y=\"890\"/></Array></mxGeometry></mxCell><mxCell id=\"12\" value=\"BOT:您的省内流量2GB，已用流量为{%usage%}GB，剩余流量为{%left%}G；全国流量包1GB，已用流量为1GB，剩余流量为0GB。发现您的流量余额已经不足了，您是否需要续订流量包呢？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"390\" y=\"700\" width=\"200\" height=\"100\" as=\"geometry\"/></mxCell><mxCell id=\"21\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"16\" target=\"20\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"350\" y=\"1080\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"16\" value=\"INTENT:INTENT_YES\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"150\" y=\"940\" width=\"250\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"19\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=1;entryY=0.5;\" parent=\"1\" source=\"17\" target=\"53\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"560\" y=\"2375\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"17\" value=\"INTENT:INTENT_NO\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"740\" y=\"940\" width=\"270\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"25\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"20\" target=\"23\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"20\" value=\"&lt;span&gt;BOT:王女士您好，我们有省内，全国，夜间三种流量包，您是要续订什么流量包？&lt;br&gt;&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"150\" y=\"1100\" width=\"250\" height=\"90\" as=\"geometry\"/></mxCell><mxCell id=\"30\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"23\" target=\"31\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"275\" y=\"1440\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"23\" value=\"&lt;span&gt;INTENT:INTENT_BOOK_DATA_PACKAGE&lt;br&gt;SLOT:user_package_type&lt;br&gt;&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"130\" y=\"1290\" width=\"290\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"33\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"31\" target=\"32\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"31\" value=\"PARAM:slot_val:type=user_package_type&lt;br&gt;PARAM:func_val:options=demo_get_package_options:{%type%}&lt;br&gt;BOT:好的，{%type%}有如下选择：{%options%}。请问您想续订哪种？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"90\" y=\"1440\" width=\"370\" height=\"70\" as=\"geometry\"/></mxCell><mxCell id=\"34\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"32\" target=\"35\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"275\" y=\"1710\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"32\" value=\"&lt;span&gt;INTENT:INTENT_BOOK_DATA_PACKAGE&lt;br&gt;SLOT:&lt;/span&gt;user_package_type,user_package_name&lt;span&gt;&lt;br&gt;&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"130\" y=\"1580\" width=\"290\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"36\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"35\" target=\"37\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"350\" y=\"1810\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"35\" value=\"PARAM:slot_val:type=user_package_type&lt;br&gt;PARAM:slot_val:name=user_package_name&lt;span&gt;&lt;br&gt;BOT:&lt;/span&gt;好的王女士，您是想续订{%name%}的{%type%}吗？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"100\" y=\"1720\" width=\"350\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"38\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"37\" target=\"53\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"275\" y=\"1970\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"37\" value=\"&lt;span&gt;INTENT:INTENT_YES&lt;br&gt;&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"130\" y=\"1830\" width=\"290\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"48\" value=\"\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" target=\"2\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"310\" y=\"20\" as=\"sourcePoint\"/><mxPoint x=\"320\" y=\"230\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"49\" value=\"\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0;entryY=0.5;\" parent=\"1\" target=\"5\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"80\" y=\"410\" as=\"sourcePoint\"/><mxPoint x=\"80\" y=\"420\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"52\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=1;entryY=0.5;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"50\" target=\"20\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"50\" value=\"&lt;span&gt;INTENT:INTENT_BOOK_DATA_PACKAGE&lt;br&gt;&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"429\" y=\"940\" width=\"290\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"54\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" source=\"53\" target=\"55\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"275\" y=\"2150\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"53\" value=\"&lt;span&gt;BOT:好的王女士，请问还有什么可以帮助您的吗&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"125\" y=\"2000\" width=\"300\" height=\"90\" as=\"geometry\"/></mxCell><mxCell id=\"57\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"55\" target=\"56\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"55\" value=\"&lt;span&gt;INTENT:INTENT_NO&lt;br&gt;&lt;/span&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"130\" y=\"2150\" width=\"290\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"56\" value=\"&lt;span&gt;BOT:好的，很高兴为您服务&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"125\" y=\"2290\" width=\"300\" height=\"90\" as=\"geometry\"/></mxCell><mxCell id=\"59\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;jettySize=auto;orthogonalLoop=1;strokeWidth=2;entryX=1;entryY=0;\" parent=\"1\" target=\"50\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"><mxPoint x=\"750\" y=\"810\" as=\"targetPoint\"/><mxPoint x=\"677\" y=\"610\" as=\"sourcePoint\"/></mxGeometry></mxCell><mxCell id=\"63\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" parent=\"1\" source=\"60\" target=\"61\" edge=\"1\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"60\" value=\"INTENT:INTENT_REPEAT\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"590\" y=\"80\" width=\"240\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"61\" value=\"PARAM:&lt;span&gt;session_state&lt;/span&gt;:state=&lt;span&gt;&lt;br&gt;BOT:{%&lt;/span&gt;&lt;span&gt;dmkit_param_last_tts&lt;/span&gt;&lt;span&gt;%}&lt;/span&gt;&lt;br&gt;&lt;span&gt;STATE:{%state%}&lt;br&gt;&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"580\" y=\"230\" width=\"260\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"62\" value=\"\" style=\"endArrow=classic;html=1;strokeWidth=2;entryX=0.5;entryY=0;\" parent=\"1\" target=\"60\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"710\" y=\"20\" as=\"sourcePoint\"/><mxPoint x=\"740\" y=\"20\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"67\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" edge=\"1\" parent=\"1\" source=\"64\" target=\"66\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"64\" value=\"INTENT:INTENT_WAIT\" style=\"ellipse;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"960\" y=\"80\" width=\"240\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"65\" value=\"\" style=\"endArrow=classic;html=1;strokeWidth=2;entryX=0.5;entryY=0;\" edge=\"1\" parent=\"1\" target=\"64\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"1080\" y=\"20\" as=\"sourcePoint\"/><mxPoint x=\"1069.5\" y=\"70\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"71\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" edge=\"1\" parent=\"1\" source=\"66\" target=\"70\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"66\" value=\"PARAM:session_state:&lt;span&gt;dmkit_param_context_state&lt;/span&gt;&lt;span&gt;=&lt;br&gt;&lt;/span&gt;PARAM:string:dmkit_param_context_tts={%dmkit_param_last_tts%}&lt;br&gt;&lt;span&gt;BOT:&lt;/span&gt;&lt;span lang=&quot;ZH-CN&quot;&gt;嗯，您说？&lt;/span&gt;&lt;span&gt;&lt;br&gt;&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"880\" y=\"230\" width=\"400\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"73\" style=\"edgeStyle=orthogonalEdgeStyle;rounded=1;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;jettySize=auto;orthogonalLoop=1;strokeWidth=2;\" edge=\"1\" parent=\"1\" source=\"70\" target=\"72\"><mxGeometry relative=\"1\" as=\"geometry\"/></mxCell><mxCell id=\"70\" value=\"INTENT:INTENT_CONTINUE\" style=\"ellipse;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"960\" y=\"350\" width=\"240\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"72\" value=\"&lt;span&gt;BOT:{%&lt;/span&gt;dmkit_param_context_tts&lt;span&gt;%}&lt;/span&gt;&lt;br&gt;&lt;span&gt;STATE:{%&lt;/span&gt;dmkit_param_context_state&lt;span&gt;%}&lt;br&gt;&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"880\" y=\"500\" width=\"400\" height=\"60\" as=\"geometry\"/></mxCell></root></mxGraphModel>"
  },
  {
    "path": "conf/app/demo/quota_adjust.json",
    "content": "[\n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": [\n              \"您需要调整临时额度还是固定额度？\", \n              \"请问您要调整固定额度还是临时额度呢？\"\n            ]\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"001\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [\n          {\n            \"type\": \"eq\", \n            \"value\": \"{%type%},临时\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"临时额度只能提升，请问您是否需要提升临时额度？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"007\"\n        }\n      }, \n      {\n        \"assertion\": [\n          {\n            \"type\": \"eq\", \n            \"value\": \"{%type%},固定\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您需要提升额度还是降低额度？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [\n          {\n            \"type\": \"eq\", \n            \"value\": \"{%type%},临时\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"临时额度只能提升，请问您是否需要提升临时额度？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"007\"\n        }\n      }, \n      {\n        \"assertion\": [\n          {\n            \"type\": \"eq\", \n            \"value\": \"{%type%},固定\"\n          }\n        ], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您需要提升额度还是降低额度？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"002\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\"\n      ], \n      \"state\": \"001\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问您要{%method%}到多少呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_method\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问您要{%method%}到多少呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_method\"\n      ], \n      \"state\": \"010\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问您要{%method%}到多少呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"003\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_method\"\n      ], \n      \"state\": \"002\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您确认要将银行卡{%type%}{%method%}至{%amount%}吗？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }, \n      {\n        \"name\": \"amount\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_amount\"\n      }, \n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_method\", \n        \"user_amount\"\n      ], \n      \"state\": \"003\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您确认要将银行卡{%type%}{%method%}至{%amount%}吗？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"004\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }, \n      {\n        \"name\": \"amount\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_amount\"\n      }, \n      {\n        \"name\": \"type\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_type\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_method\", \n        \"user_amount\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": [\n              \"很高兴为您服务，还有其他需要帮助的吗？\", \n              \"好的，请问还有其他能帮到您的吗？\"\n            ]\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"005\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"004\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": [\n              \"很高兴为您服务，还有其他需要帮助的吗？\", \n              \"好的，请问还有其他能帮到您的吗？\"\n            ]\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"005\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"011\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"很高兴为您服务，王女士再见！\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"006\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"009\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"很高兴为您服务，王女士再见！\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"006\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"005\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"好的王女士，请问您要提升到多少呢？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"008\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_YES\", \n      \"slots\": [], \n      \"state\": \"007\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"不好意思，临时额度只能提升，请问还有其他需要帮助的吗？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"009\"\n        }\n      }\n    ], \n    \"params\": [], \n    \"trigger\": {\n      \"intent\": \"INTENT_NO\", \n      \"slots\": [], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您是要{%method%}固定额度还是临时额度？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"010\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"method\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_method\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_method\"\n      ], \n      \"state\": \"\"\n    }\n  }, \n  {\n    \"output\": [\n      {\n        \"assertion\": [], \n        \"result\": [\n          {\n            \"type\": \"tts\", \n            \"value\": \"您确认要将银行卡临时额度提升至{%amount%}吗？\"\n          }\n        ], \n        \"session\": {\n          \"context\": {}, \n          \"state\": \"011\"\n        }\n      }\n    ], \n    \"params\": [\n      {\n        \"name\": \"amount\", \n        \"type\": \"slot_val\", \n        \"value\": \"user_amount\"\n      }\n    ], \n    \"trigger\": {\n      \"intent\": \"INTENT_ADJUST_QUOTA\", \n      \"slots\": [\n        \"user_type\", \n        \"user_amount\"\n      ], \n      \"state\": \"008\"\n    }\n  }\n]\n"
  },
  {
    "path": "conf/app/demo/quota_adjust.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<mxGraphModel dx=\"919\" dy=\"541\" grid=\"1\" gridSize=\"10\" guides=\"1\" tooltips=\"1\" connect=\"1\" arrows=\"1\" fold=\"1\" page=\"1\" pageScale=\"1\" pageWidth=\"1169\" pageHeight=\"1654\" background=\"#ffffff\" math=\"0\" shadow=\"0\"><root><mxCell id=\"0\"/><mxCell id=\"1\" parent=\"0\"/><mxCell id=\"2\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"305\" y=\"50\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"4\" value=\"BOT: 您需要调整临时额度还是固定额度？| 请问您要调整固定额度还是临时额度呢？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"305\" y=\"160\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"7\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"2\" target=\"4\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"160\" y=\"170\" as=\"sourcePoint\"/><mxPoint x=\"210\" y=\"120\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"8\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"4\" target=\"9\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"200\" y=\"380\" as=\"sourcePoint\"/><mxPoint x=\"365\" y=\"250\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"9\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;SLOT: user_type&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"305\" y=\"260\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"12\" value=\"BOT: 您需要提升额度还是降低额度？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"186.5\" y=\"520\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"14\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;SLOT: user_type, user_method&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"186.5\" y=\"630\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"19\" value=\"PARAM: slot_val: method = user_method&lt;br&gt;BOT: 好的王女士，请问您要{%method%} 到多少呢？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"186.5\" y=\"767\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"21\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;SLOT: user_type, user_method, user_amount&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"186.5\" y=\"890\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"23\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"14\" target=\"19\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"101.5\" y=\"850\" as=\"sourcePoint\"/><mxPoint x=\"151.5\" y=\"800\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"24\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"19\" target=\"21\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"131.5\" y=\"1030\" as=\"sourcePoint\"/><mxPoint x=\"181.5\" y=\"980\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"27\" value=\"PARAM: slot_val: method = user_method&lt;br&gt;PARAM: slot_val: amount = user_amount&lt;br&gt;PARAM: slot_val: type&amp;nbsp;= user_type&lt;br&gt;BOT: 您确认要将银行卡{%type%} {%method%} 至 {%amount%} 吗？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"40\" y=\"1060\" width=\"411\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"28\" value=\"\" style=\"endArrow=classic;html=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"21\" target=\"27\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"211.5\" y=\"1200\" as=\"sourcePoint\"/><mxPoint x=\"261.5\" y=\"1150\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"29\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"27\" target=\"30\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"171.5\" y=\"1200\" as=\"sourcePoint\"/><mxPoint x=\"271.5\" y=\"1110\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"30\" value=\"INTENT: INTENT_YES\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"185\" y=\"1200\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"31\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"30\" target=\"32\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"351.5\" y=\"1240\" as=\"sourcePoint\"/><mxPoint x=\"271.5\" y=\"1220\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"32\" value=\"BOT: 很高兴为您服务，还有其他需要帮助的吗？| 好的，请问还有其他能帮到您的吗？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"185\" y=\"1320\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"38\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"32\" target=\"39\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"411.5\" y=\"1360\" as=\"sourcePoint\"/><mxPoint x=\"461.5\" y=\"1310\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"39\" value=\"INTENT: INTENT_NO\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"185\" y=\"1430\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"40\" value=\"BOT: 很高兴为您服务，王女士再见！&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"185\" y=\"1560\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"41\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"39\" target=\"40\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"391.5\" y=\"1420\" as=\"sourcePoint\"/><mxPoint x=\"441.5\" y=\"1370\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"43\" value=\"BOT: 临时额度只能提升，请问您是否需要提升临时额度？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"426.5\" y=\"520\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"44\" value=\"INTENT: INTENT_YES&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"395\" y=\"640\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"47\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"44\" target=\"48\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"791.5\" y=\"820\" as=\"sourcePoint\"/><mxPoint x=\"721.5\" y=\"760\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"48\" value=\"BOT: 好的王女士，请问您要提升到多少呢？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"395\" y=\"767\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"53\" value=\"INTENT: INTENT_NO&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"611.5\" y=\"640\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"54\" value=\"\" style=\"endArrow=classic;html=1;entryX=0.5;entryY=0;exitX=0.5;exitY=1;\" parent=\"1\" source=\"53\" target=\"55\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"700\" y=\"740\" as=\"sourcePoint\"/><mxPoint x=\"671.5\" y=\"760\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"55\" value=\"BOT: 不好意思，临时额度只能提升，请问还有其他需要帮助的吗？&lt;br&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"611.5\" y=\"770\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"58\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"12\" target=\"14\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"121.5\" y=\"750\" as=\"sourcePoint\"/><mxPoint x=\"171.5\" y=\"700\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"63\" value=\"\" style=\"endArrow=classic;html=1;entryX=0.5;entryY=0;\" parent=\"1\" target=\"2\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"365\" y=\"10\" as=\"sourcePoint\"/><mxPoint x=\"130\" y=\"110\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"64\" value=\"\" style=\"endArrow=classic;html=1;entryX=0;entryY=0.5;\" parent=\"1\" target=\"9\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"230\" y=\"300\" as=\"sourcePoint\"/><mxPoint x=\"260\" y=\"290\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"65\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"9\" target=\"69\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"490\" y=\"450\" as=\"sourcePoint\"/><mxPoint x=\"410\" y=\"350\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"69\" value=\"PARAM: slot_val: type = user_type\" style=\"rhombus;whiteSpace=wrap;html=1;rounded=0;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"275\" y=\"400\" width=\"180\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"70\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" source=\"69\" target=\"12\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"150\" y=\"510\" as=\"sourcePoint\"/><mxPoint x=\"200\" y=\"460\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"72\" value=\"eq: {%type%}, 固定\" style=\"text;html=1;resizable=0;points=[];align=center;verticalAlign=middle;labelBackgroundColor=#ffffff;\" parent=\"70\" vertex=\"1\" connectable=\"0\"><mxGeometry x=\"0.1013\" y=\"-1\" relative=\"1\" as=\"geometry\"><mxPoint as=\"offset\"/></mxGeometry></mxCell><mxCell id=\"71\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" source=\"69\" target=\"43\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"470\" y=\"490\" as=\"sourcePoint\"/><mxPoint x=\"520\" y=\"440\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"73\" value=\"eq: {%type%}, 临时&lt;br&gt;\" style=\"text;html=1;resizable=0;points=[];align=center;verticalAlign=middle;labelBackgroundColor=#ffffff;\" parent=\"71\" vertex=\"1\" connectable=\"0\"><mxGeometry x=\"-0.037\" relative=\"1\" as=\"geometry\"><mxPoint as=\"offset\"/></mxGeometry></mxCell><mxCell id=\"74\" value=\"\" style=\"endArrow=classic;html=1;entryX=0;entryY=0.5;\" parent=\"1\" target=\"14\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"110\" y=\"670\" as=\"sourcePoint\"/><mxPoint x=\"100\" y=\"650\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"75\" value=\"\" style=\"endArrow=classic;html=1;entryX=0;entryY=0.5;\" parent=\"1\" target=\"21\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"100\" y=\"930\" as=\"sourcePoint\"/><mxPoint x=\"130\" y=\"910\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"81\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" source=\"43\" target=\"44\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"680\" y=\"630\" as=\"sourcePoint\"/><mxPoint x=\"730\" y=\"580\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"82\" value=\"\" style=\"endArrow=classic;html=1;entryX=0.5;entryY=0;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" target=\"53\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"490\" y=\"580\" as=\"sourcePoint\"/><mxPoint x=\"670\" y=\"620\" as=\"targetPoint\"/><Array as=\"points\"><mxPoint x=\"490\" y=\"610\"/><mxPoint x=\"672\" y=\"610\"/></Array></mxGeometry></mxCell><mxCell id=\"88\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=1;entryY=0.5;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" source=\"55\" target=\"39\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"680\" y=\"970\" as=\"sourcePoint\"/><mxPoint x=\"490\" y=\"1190\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"89\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;SLOT: user_method&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=0;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"540\" y=\"260\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"90\" value=\"\" style=\"endArrow=classic;html=1;entryX=0.5;entryY=0;\" parent=\"1\" target=\"89\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"600\" y=\"210\" as=\"sourcePoint\"/><mxPoint x=\"720\" y=\"410\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"92\" value=\"PARAM: slot_val: method = user_method&lt;br&gt;BOT:&amp;nbsp; 您是要{%method%}固定额度还是临时额度？\" style=\"rounded=1;whiteSpace=wrap;html=1;\" parent=\"1\" vertex=\"1\"><mxGeometry x=\"540\" y=\"380\" width=\"120\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"93\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" parent=\"1\" source=\"89\" target=\"92\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"750\" y=\"550\" as=\"sourcePoint\"/><mxPoint x=\"770\" y=\"330\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"94\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=1;entryY=0;edgeStyle=orthogonalEdgeStyle;\" parent=\"1\" source=\"92\" target=\"14\" edge=\"1\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"680\" y=\"560\" as=\"sourcePoint\"/><mxPoint x=\"730\" y=\"510\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"95\" value=\"INTENT: INTENT_ADJUST_QUOTA&lt;br&gt;SLOT: user_type, user_amount&lt;br&gt;\" style=\"ellipse;whiteSpace=wrap;html=1;rounded=0;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"395\" y=\"890\" width=\"120\" height=\"80\" as=\"geometry\"/></mxCell><mxCell id=\"96\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.5;entryY=0;\" edge=\"1\" parent=\"1\" source=\"48\" target=\"95\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"610\" y=\"1000\" as=\"sourcePoint\"/><mxPoint x=\"660\" y=\"950\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"97\" value=\"&lt;span&gt;PARAM: slot_val: amount = user_amount&lt;/span&gt;&lt;br&gt;&lt;span&gt;BOT: 您确认要将银行卡临时额度提升至 {%amount%} 吗？&lt;/span&gt;\" style=\"rounded=1;whiteSpace=wrap;html=1;\" vertex=\"1\" parent=\"1\"><mxGeometry x=\"504\" y=\"1060\" width=\"335\" height=\"60\" as=\"geometry\"/></mxCell><mxCell id=\"98\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.5;exitY=1;entryX=0.25;entryY=0;edgeStyle=orthogonalEdgeStyle;\" edge=\"1\" parent=\"1\" source=\"95\" target=\"97\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"620\" y=\"1020\" as=\"sourcePoint\"/><mxPoint x=\"670\" y=\"970\" as=\"targetPoint\"/></mxGeometry></mxCell><mxCell id=\"99\" value=\"\" style=\"endArrow=classic;html=1;exitX=0.25;exitY=1;entryX=1;entryY=0.5;edgeStyle=orthogonalEdgeStyle;\" edge=\"1\" parent=\"1\" source=\"97\" target=\"30\"><mxGeometry width=\"50\" height=\"50\" relative=\"1\" as=\"geometry\"><mxPoint x=\"490\" y=\"1290\" as=\"sourcePoint\"/><mxPoint x=\"540\" y=\"1240\" as=\"targetPoint\"/></mxGeometry></mxCell></root></mxGraphModel>"
  },
  {
    "path": "conf/app/products.json",
    "content": "{\n    \"default\": {\n        \"4050\": {\n            \"score\": 1,\n            \"conf_path\": \"conf/app/demo/cellular_data.json\"\n        },\n        \"1234\": {\n            \"score\": 1,\n            \"conf_path\": \"conf/app/demo/quota_adjust.json\"\n        },\n        \"11669\": {\n            \"score\": 1,\n            \"conf_path\": \"conf/app/demo/book_hotel.json\"\n        }\n    }\n}\n\n"
  },
  {
    "path": "conf/app/remote_services.json",
    "content": "{\n    \"unit_bot\": {\n        \"naming_service_url\": \"https://aip.baidubce.com\",\n        \"load_balancer_name\": \"\",\n        \"protocol\": \"http\",\n        \"client\": \"brpc\",\n        \"timeout_ms\": 3000,\n        \"retry\": 1,\n        \"headers\": {\n            \"Host\": \"aip.baidubce.com\",\n            \"Content-Type\": \"application/json\"\n        }\n    },\n    \"token_auth\": {\n        \"naming_service_url\": \"https://aip.baidubce.com\",\n        \"load_balancer_name\": \"\",\n        \"protocol\": \"http\",\n        \"client\": \"brpc\",\n        \"timeout_ms\": 3000,\n        \"retry\": 1,\n        \"headers\": {\n            \"Host\": \"aip.baidubce.com\"\n        }\n    },\n    \"hotel_service\": {\n        \"naming_service_url\": \"http://127.0.0.1:5000\",\n        \"load_balancer_name\": \"random\",\n        \"protocol\": \"http\",\n        \"client\": \"brpc\",\n        \"timeout_ms\": 3000,\n        \"retry\": 1,\n        \"headers\": {\n        }\n    }\n}\n"
  },
  {
    "path": "conf/gflags.conf",
    "content": "# TCP Port of this server\n--port=8010\n\n# Only allow builtin services at this port\n--internal_port=8011\n\n# Connection will be closed if there is no read/write operations during this time\n--idle_timeout_s=-1\n\n# Limit of requests processing in parallel\n--max_concurrency=0\n\n# Url path of the app\n--url_path=/search\n\n# Log to file\n--log_to_file=true\n\n"
  },
  {
    "path": "deps.sh",
    "content": "#!/usr/bin/env bash\n\ncd \"$(dirname \"$0\")\"\nJOBS=8\nOS=$1\ncase \"$OS\" in\nmac)\n    ;;\nubuntu)\n    ;;\ncentos)\n    ;;\nnone)\n    ;;\n*)\n    echo \"Usage: $0 [ubuntu|mac|centos|none]\"\n    exit 1\nesac\n\nif [ $OS = mac ]; then\n    echo \"Installing dependencies for MacOS...\"\n    brew install openssl git gnu-getopt gflags protobuf leveldb cmake openssl\nelif [ $OS = ubuntu ]; then\n    echo \"Installing dependencies for Ubuntu...\"\n    sudo apt-get install -y git \\\n        g++ \\\n        make \\\n        libssl-dev \\\n        coreutils \\\n        libgflags-dev \\\n        libprotobuf-dev \\\n        libprotoc-dev \\\n        protobuf-compiler \\\n        libleveldb-dev \\\n        libsnappy-dev \\\n        libcurl4-openssl-dev \\\n        libgoogle-perftools-dev\nelif [ $OS = centos ]; then\n    echo \"Installing dependencies for CentOS...\"\n    sudo yum install -y epel-release\n    sudo yum install -y git gcc-c++ make openssl-devel libcurl-devel\n    sudo yum install -y gflags-devel protobuf-devel protobuf-compiler leveldb-devel gperftools-devel\nelse\n    echo \"Skipping dependencies installation...\"\nfi\n\n\nif [ ! -e brpc ]; then\n    echo \"Cloning brpc...\"\n    git clone https://github.com/brpc/brpc.git\nfi\ncd brpc\ngit checkout master\ngit pull\ngit checkout 2ae7f04ce513c6aee27545df49d5439a98ae3a3f\n\n#build brpc\necho \"Building brpc...\"\nrm -rf _build\nmkdir -p _build\ncd _build\ncmake ..\nmake -j$JOBS\n\ncd ../../\n\n"
  },
  {
    "path": "docs/demo_book_hotel_pattern.txt",
    "content": "INTENT_BOOK_HOTEL\t0.8\t[D:user_hotel]#@##0#@##1\t1\nINTENT_YES\t0.7\t[D:kw_yes]#@##0#@##1\t1\nINTENT_NO\t0.7\t[D:kw_no]#@##0#@##1\t1\nINTENT_BOOK_HOTEL\t0.7\t[D:kw_book]#@##0#@##1#@@##[D:kw_hotel]#@##0#@##1#@@##[D:user_time]#@##0#@##0#@@##[D:user_room_type]#@##0#@##0#@@##[D:user_hotel]#@##0#@##0#@@##[D:user_location]#@##0#@##0\t1\n"
  },
  {
    "path": "docs/demo_cellular_data_pattern.txt",
    "content": "INTENT_CONTINUE\t0.8\t[D:kw_continue]#@##0#@##1\t1\nINTENT_WAIT\t0.8\t[D:kw_wait]#@##0#@##1\t1\nINTENT_CHECK_DATA_USAGE\t0.8\t[D:user_time]#@##0#@##1\t1\nINTENT_REPEAT\t0.7\t[D:kw_repeat]#@##0#@##1\t1\nINTENT_BOOK_DATA_PACKAGE\t0.9\t[D:user_package_type]#@##0#@##1\t1\nINTENT_BOOK_DATA_PACKAGE\t0.9\t[D:kw_book]#@##0#@##1#@@##[D:kw_package]#@##0#@##0#@@##[D:user_package_type]#@##0#@##0#@@##[D:user_package_name]#@##0#@##0\t1\nINTENT_CHECK_DATA_USAGE\t0.9\t[D:kw_check]#@##0#@##1#@@##[D:user_time]#@##0#@##0#@@##[D:kw_data_usage]#@##0#@##1\t1\nINTENT_NO\t0.9\t[D:kw_no]#@##0#@##1\t1\nINTENT_YES\t0.9\t[D:kw_yes]#@##0#@##1\t1\n"
  },
  {
    "path": "docs/demo_quota_adjust_pattern.txt",
    "content": "INTENT_NO\t0.9\t[D:kw_no]#@##0#@##1\t1\nINTENT_YES\t0.9\t[D:kw_yes]#@##0#@##1\t1\nINTENT_ADJUST_QUOTA\t0.9\t[D:kw_adjust]#@##0#@##0#@@##[D:kw_quota]#@##0#@##0#@@##[D:user_type]#@##0#@##0#@@##[D:user_method]#@##0#@##0#@@##[D:user_amount]#@##0#@##0\t1\n"
  },
  {
    "path": "docs/demo_skills.md",
    "content": "# DMKit示例场景\n\n## 查询流量及续订\n\n该场景实现一个简单的手机流量查询及续订流量包的技能。\n\n### 查询流量及续订 - UNIT平台配置\n\n一共分为以下几个步骤：\n\n* 创建技能\n* 配置意图\n* 配置词槽\n* 添加词槽的词典值\n* 添加特征词列表\n* 导入对话模板\n\n#### 创建BOT\n\n1. 进入[百度理解与交互(unit)平台](http://ai.baidu.com/unit/v2#/sceneliblist)\n2. 新建一个技能给查询流量及续订的demo使用。\n\n#### 配置意图\n\n1. 点击进入技能，新建对话意图，以INTENT_CHECK_DATA_USAGE为例。\n2. 意图名称填写INTENT_CHECK_DATA_USAGE。\n3. 意图别名可以根据自己偏好填写，比如填写查询手机流量。\n4. 添加词槽。INTENT_CHECK_DATA_USAGE 所需的词槽为 user_time;\n5. 词槽别名可以根据自己偏好填写，比如填写查询时间，查询月份等。\n6. 添加完词槽名和词槽别名以后，点击下一步，进入到选择词典环节，user_time选择系统词槽词典中的 **sys_time(时间)** 词槽。\n7. 点击下一步，词槽必填选项选择非必填，点击确认。\n\n** 其他两个user_package_type和user_package_name的词槽使用自定义词典，将下方词槽对应的词典内容自行粘贴到txt中上传即可**\n\n全部意图包括列表如下：\n\n* INTENT_CHECK_DATA_USAGE，所需词槽为 user_time\n* INTENT_BOOK_DATA_PACKAGE，所需词槽为 user_package_type，user_package_name\n* INTENT_YES\n* INTENT_NO\n* INTENT_REPEAT\n* INTENT_WAIT\n* INTENT_CONTINUE\n\n词槽列表：\n\n* user_time，使用系统时间词槽\n\n* user_package_type\n  \n    ```text\n    省内\n    #省内流量\n    全国\n    #全国流量\n    夜间\n    #夜间流量\n    ```\n* user_package_name\n    ```text\n    10元100M\n    #10元100兆\n    #十元一百M\n    #十元一百兆\n    20元300M\n    #20元300兆\n    #二十元三百M\n    #二十元三百兆\n    50元1G\n    #五十元1G\n    ```\n\n#### 新增特征词\n\n点击**效果优化**中的**对话模板**，选择下方的新建特征词，将名称和词典值依次填入。eg：kw_check即为名称，名称下方为词典值，直接复制粘贴即可。\n\n特征词列表如下：\n\n* kw_check\n    ```text\n    查一查\n    查询\n    ```\n* kw_data_usage\n    ```text\n    流量\n    流量情况\n    流量使用情况\n    流量使用\n    ```\n* kw_book\n    ```text\n    续定\n    续订\n    预定\n    预订\n    ```\n* kw_package\n    ```text\n    流量包\n    流量套餐\n    ```\n* kw_yes\n    ```text\n    是\n    好\n    对\n    想\n    要\n    是的\n    好的\n    对的\n    我想\n    我要\n    可以\n    行的\n    需要\n    没问题\n    ```\n* kw_no\n    ```text\n    不\n    不想\n    不要\n    不行\n    别\n    没有\n    没了\n    没\n    不用\n    不需要\n    没有了\n    ```\n* kw_repeat\n    ```text\n    没听清楚\n    再说一次\n    ```\n* kw_wait\n    ```text\n    稍等\n    等等\n    稍等一下\n    等一下\n    等一等\n    ```\n* kw_continue\n    ```text\n    你继续\n    您继续\n    继续\n    ```\n\n#### 导入对话模板\n\n* 完成以上步骤后，再进行该步骤，不然系统会报错\n* 将文件[demo_cellular_data_pattern.txt](demo_cellular_data_pattern.txt)下载导入即可\n\n### 查询流量及续订 - DMKit配置\n\n该场景DMKit配置为conf/app/demo/cellular_data.json文件，该文件由同目录下对应的.xml文件生成，可以将.xml文件在 <https://www.draw.io> 中导入查看。\n\n## 调整银行卡额度\n\n该场景实现一个简单的银行卡固定额度及临时额度调整的技能。\n\n### 调整银行卡额度 - UNIT平台配置\n\n平台配置参考查询流量的配置，所需的配置内容见下图。\n\n所需意图包括列表：\n\n* INTENT_ADJUST_QUOTA, 所需词槽为user_type, user_method, user_amount\n* INTENT_YES\n* INTENT_NO\n\n词槽列表：\n\n* user_amount, 复用系统sys_num词槽\n\n* user_type\n    ```text\n    固定\n    #固定额度\n    临时\n    #临时额度\n\n    ```\n\n* user_method\n    ```text\n    提升\n    #提高\n    #增加\n    降低\n    #减少\n    #下调\n    ```\n\n特征词列表：\n\n* kw_adjust\n    ```text\n    调整\n    调整一下\n    改变\n    ```\n* kw_quota\n    ```text\n    额度\n    银行卡额度\n    信用卡额度\n    ```\n\n* kw_yes\n    ```text\n    是\n    好\n    对\n    想\n    要\n    是的\n    好的\n    对的\n    我想\n    我要\n    可以\n    行的\n    没问题\n    ```\n* kw_no\n    ```text\n    不\n    不想\n    不要\n    不对\n    错了\n    不是\n    别\n    没有\n    没了\n    没\n    不用\n    没有了\n    ```\n\n对话模板：\n\n* 将文件[demo_quota_adjust_pattern.txt](demo_quota_adjust_pattern.txt)下载导入即可\n\n### 调整银行卡额度 - DMKit配置\n\n该场景DMKit配置为conf/app/demo/quota_adjust.json文件，该文件由同目录下对应的.xml文件生成，可以将.xml文件在 <https://www.draw.io> 中导入查看。\n\n## 预订酒店\n\n该场景实现一个简单的预订酒店的技能。\n\n### 预订酒店 - UNIT平台配置\n\n平台配置参考查询流量的配置，所需的配置内容见下图。\n\n所需意图包括列表：\n\n* INTENT_BOOK_HOTEL, 所需词槽为user_time, user_room_type, user_location, user_hotel\n* INTENT_YES\n* INTENT_NO\n\n词槽列表：\n\n* user_time, 复用系统sys_time词槽。需要设置为必填词槽，澄清话术配置为『请问您要预订哪一天的酒店？』\n\n* user_room_type。需要设置为必填词槽，澄清话术配置为『请问您要预订哪个房型？』\n    ```text\n    标间\n    大床房\n    单人间\n    双人间\n    双床房\n    标准房\n    标准间\n    ```\n\n* user_hotel, 复用系统sys_loc_hotel词槽\n\n* user_location, 复用系统sys_loc词槽\n\n特征词列表：\n\n* kw_book\n    ```text\n    定\n    预定\n    订\n    预订\n    ```\n* kw_hotel\n    ```text\n    旅馆\n    酒店\n    ```\n\n* kw_yes\n    ```text\n    是\n    好\n    对\n    想\n    要\n    是的\n    好的\n    对的\n    我想\n    我要\n    可以\n    行的\n    没问题\n    确认\n    ```\n\n* kw_no\n    ```text\n    不\n    不想\n    不要\n    不对\n    不是\n    不用\n    不行\n    不可以\n    别\n    没\n    没有\n    没了\n    没有了\n    错了\n    ```\n\n对话模板：\n\n* 将文件[demo_book_hotel_pattern.txt](demo_book_hotel_pattern.txt)下载导入即可\n\n### 预订酒店 - DMKit配置\n\n该场景DMKit配置为conf/app/demo/book_hotel.json文件，该文件由同目录下对应的.xml文件生成，可以将.xml文件在 <https://www.draw.io> 中导入查看。\n"
  },
  {
    "path": "docs/faq.md",
    "content": "# DMKit 常见问题\n\n## 编译brpc失败\n\n参考BRPC官方文档 <https://github.com/brpc/brpc/>，检查是否已安装所需依赖库。建议使用系统Ubuntu 16.04或者CentOS 7。更多BRPC相关问题请在BRPC github库提起issue。\n\n## 返回错误信息 DM policy resolve failed\n\nDMKit通过UNIT云端技能解析出的用户query的意图和词槽之后，需要根据对话意图结合当前对话状态在DMKit配置中对应的policy处理对话流程。当用户query解析出的意图结合当前对话状态未能找到可选的policy或者选中policy执行流程出错时，DMKit返回错误信息DM policy resolve failed。开发者需要检查：1)当前技能配置是否在products.json文件中进行注册；2）当前query解析结果意图在技能配置中是否配置了policy，详细配置说明参考[DMKit快速上手](tutorial.md)；3）检查DMKit日志查看policy执行流程是否出错，。\n\n## 返回错误信息 Failed to call unit bot api\n\nDMKit访问UNIT云端失败。具体原因需要查看DMKit服务日志，常见原因是请求超时。\n对于请求超时的情况，先检查DMKit所在服务器网络连接云端（默认地址为 aip.baidubce.com）是否畅通，尝试修改conf/app/remote_services.json文件中unit_bot服务对应超时时间。如果连接没有问题且增大超时时间无效，则尝试切换请求client：DMKit默认使用BRPC client请求UNIT云端，目前发现偶然情况下HTTPS访问云端出现卡死而返回超时错误。DMKit支持切换为curl方式访问云端，将conf/app/remote_services.json配置中client值由brpc修改为curl即可。需要注意使用curl方式时，建议升级openssl版本不低于1.1.0，libcurl版本不低于7.32。\n\n## 返回错误信息 Unsupported action type satisfy\n\n使用DMKit需要将UNIT平台中【技能设置->高级设置】中【对话回应设置】一项设置为『使用DMKit配置』。设置该选项之后，UNIT云端使用DMKit支持的数据协议。如设置为『在UNIT平台上配置』, DMKit无法识别UNIT云端数据协议，将返回错误Unsupported action type satisfy。\n\n## DMKit如何支持FAQ问答对\n\n目前UNIT平台中将【对话回应】设置为【使用DMKit配置】之后，如果对话触发了平台配置的FAQ问答集，平台返回结果不会将答案赋值给response中的say字段，但是会将答案赋值给名为qid的词槽值。因此，结合DMKit配置可以从词槽qid解析出问答回复后进行返回。例如，平台创建问题意图FAQ_HELLO之后，可以在DMKit对应技能的policy配置中添加一下policy支持FAQ_HELLO问答意图下的所有问答集：\n\n```json\n{\n  \"trigger\": {\n    \"intent\": \"FAQ_HELLO\",\n    \"slots\": [],\n    \"state\": \"\"\n  },\n  \"params\": [\n    {\n      \"name\": \"answer_list\",\n      \"type\": \"slot_val\",\n      \"value\": \"qid\"\n    },\n    {\n      \"name\": \"faq_answer\",\n      \"type\": \"func_val\",\n      \"value\": \"split_and_choose:{%answer_list%},|,random\"\n    }\n  ],\n  \"output\": [\n    {\n      \"assertion\": [],\n      \"session\": {\n        \"context\": {},\n        \"state\": \"001\"\n      },\n      \"result\": [\n        {\n          \"type\": \"tts\",\n          \"value\": \"{%faq_answer%}\"\n        }\n      ]\n    }\n  ]\n}\n```\n"
  },
  {
    "path": "docs/tutorial.md",
    "content": "# DMKit 快速上手\n\n## 简介\n\n在任务型对话系统（Task-Oriented Dialogue System）中，一般包括了以下几个模块：\n\n* Automatic Speech Recognition（ASR），即语音识别模块，将音频转化为文本输入。\n* Natural Language Understanding（NLU），即自然语言理解模块，通过分析文本输入，解析得到对话意图与槽位（Intent + Slots）。\n* Dialog Manager（DM），即对话管理模块，根据NLU模块分析得到的意图+槽位值，结合当前对话状态，执行对应的动作并返回结果。其中执行的动作可能涉及到对内部或外部知识库的查询。\n* Natural Language Generation（NLG），即自然语言生成。目前一般采用模板的形式。\n* Text To Speech（TTS），即文字转语音模块，将对话系统的文本输出转化为音频。\n\nDMKit关注其中的对话管理模块（Dialog Manager），解决对话系统中状态管理、对话逻辑处理等问题。在实际应用中，单个技能下对话逻辑一般都是根据NLU结果中意图与槽位值，结合当前对话状态，确定需要进行处理的子流程。子流程或者返回固定话术结果，或者根据NLU中槽位值与对话状态访问内部或外部知识库获取资源数据并生成话术结果返回，在返回结果的同时也对对话状态进行更新。我们将这部分对话处理逻辑进行抽象，提供一个通过配置快速构建对话流程，可复用的对话管理模块，即Reusable Dialog Manager。\n\n## 架构\n\n![DMKit架构](dmkit.png)\n\n如上图所示，系统核心是一个对话管理引擎，在对话管理引擎的基础上，每个技能的实现都是通过一个配置文件来对对话逻辑和流程进行描述，这样每个技能仅需要关注自身对话逻辑，不需要重复开发框架代码。一个技能的配置包括了一系列的policy，每个policy包括三部分：触发条件（trigger），参数变量（params），以及输出（output）。\n\n* 触发条件（trigger）包括了NLU解析得到的意图+槽位值，以及当前的对话状态，限定了该policy被触发的条件；\n\n* 参数变量（params）是该policy运行需要的一些数据变量的定义，可以包括NLU解析结果中的槽位值、session中的变量值以及函数运行结果等。这里的函数需要在系统中进行注册，例如发送网络请求获取数据这样的函数，这些通用的函数在各个技能间都能共享，特殊情况下个别技能会需要定制化注册自己的函数；\n\n* 输出结果（output）即为该policy运行返回作为对话系统的结果，可以包括话术tts及指令，同时还可对对话状态进行更新以及写入session变量。这里的结果可以使用已定义的参数变量进行模板填充。\n\n在技能基础配置之上，还衍生出了一系列扩展功能。例如我们对一些仅需要触发条件及输出的技能，我们可以设计更精简的语法，使用更简洁的配置描述对话policy；对于多状态跳转的场景，我们引入了可视化的编辑工具，来描述对话跳转逻辑。精简语法表示及可视化编辑都可以自动转化为对话管理引擎可执行的配置，在系统中运行。\n\n## 使用DMKit搭建对话技能的一般步骤\n\nDMKit依托UNIT提供的自然语言理解能力，在此基础上搭建对话技能的一般步骤为：\n\n* 通过UNIT平台创建技能，配置技能对话流程所需的意图解析能力；\n\n* 编写技能的policy配置，policy配置文件语法见[技能配置](#技能配置)。对于对话状态状态繁多，跳转复杂的技能，可以借助[可视化配置工具](visual_tool.md)进行可视化编辑并导出技能配置。\n\n* 将UNIT平台所创建技能的id与其对应policy配置文件注册于DMKit全局注册文件，注册文件配置项见[技能注册](#技能注册)。完成之后编译运行DMKit主程序，访问DMKit[服务接口](#服务接口)即可测试对话效果。\n\n## 详细配置说明\n\n本节详细介绍实现技能功能的配置语法。所有技能的配置均位于模块源码conf/app/目录下。\n\n### 技能注册\n\nproducts.json为全局注册配置文件，默认采用以\"default\"为key的配置项，该配置项中每个技能以skill id为key，注册添加技能详细配置，配置字段解释如下：\n\n| 字段             |含义                         |\n|-----------------|-----------------------------|\n|conf_path        |技能policy配置文件地址          |\n|score            |技能排序静态分数，可设置为固定值1  |\n\n### 技能配置\n\n单个技能配置文件包括了一系列policy，每个policy字段说明如下：\n\n| 字段                             | 类型         |说明                            |\n|---------------------------------|--------------|-------------------------------|\n|trigger                          |object        | 触发节点，如果一个query满足多个policy的触发条件，则优先取state匹配的policy，再根据slot取覆盖个数最多的 |\n|+intent                          |string        | 触发所需NLU意图，意图由UNIT云端对话理解获得。此外，DMKit定义了以下预留意图：<br>dmkit_intent_fallback： 当云端返回意图在DMKit配置中未找到匹配policy时，DMKit将尝试使用该意图触发policy |\n|+slot                            |list          | 触发所需槽位值列表|\n|+state                           |string        | 触发所需状态值，即上一轮对话session中保存的state字段值 |\n|params                           |list          | 变量列表 |\n|+params[].name                   |string        | 变量名，后定义的变量可以使用已定义的变量进行模板填充，result节点中的值也可以使用变量进行模板填充。变量的使用格式为{%name%}。当name=dmkit_param_context_xxx时可以直接将该变量以xxx为key存入本轮session结果context中 |\n|+params[].type                   |string        | 变量类型，可能的类型为slot_val,request_param,session_context,func_val等，详细类型列表及说明可参照[params类型及说明](#params中变量类型列表及其说明) |\n|+params[].value                  |string        | 变量定义值 |\n|+params[].required               |bool          | 是否必须，如果必须的变量为空值时，该policy将不会返回结果 |\n|output                           |list          | 返回结果节点，可定义多个output，最终输出会按顺序选择第一个满足assertion条件的output |\n|+output[].assertion              |list          | 使用该output的前提条件列表 |\n|+output[].assertion[].type       |string        | 条件类型，详细列表及说明可参照[assertion类型及说明](#result中assertion类型说明) |\n|+output[].assertion[].value      |string        | 条件值 |\n|+output[].session                |object        | 需要保存的session数据，用于更新对话状态及记录上下文 |\n|+output[].session.state          |string        | 更新的对话状态值 |\n|+output[].session.context        |kvdict        | 写入session的变量节点，该节点下的key+value数据会存入session，再下一轮中可以在变量定义中使用 |\n|+output[].result                 |list          | 返回结果中result节点，多个result作为数组元素一起返回 |\n|+output[].result[].type          |string        | result类型 |\n|+output[].result[].value         |string        | result值            |\n\n#### params中变量类型列表及其说明：\n\n| type     |说明           |\n|----------|--------------|\n| slot_val | 从qu结果中取对应的slot值，有归一化值优先取归一化值。当对应tag值存在多个slot时，value值支持tag后按分隔符\",\"添加下标i取对应tag的第i个值（索引从0开始） |\n| request_param | 取请求参数对应的字段。这里的请求参数对应请求数据request.client_session字段中包含的K-V对，仅支持V类型为string的参数。例如request.client_session字段值为{\"param_name1\": \"param_value1\", \"param_name2\": \"param_value2\"}，定义type为request_param，value为\"param_name1\"的变量，该变量将赋值为\"param_value1\" |\n| session_context | 上一轮对话session结果中context结构体中对应的字段，例如上一轮output中session结构体保存了变量： {\"context\": {\"param_name\": \"{%param_name%}\", \"state\": \"\"}}， 本轮可定义变量{\"name\": \"param_name\", \"type\": \"session_context\", \"value\": \"param_name\"} |\n| func_val | 调用开发者定义的函数。用户定义函数位于src/user_function目录下，并需要在user_function_manager.cpp文件中进行注册。value值为\",\"连接的参数，其中第一个元素为函数名，第二个元素开始为函数参数 |\n| qu_intent | NLU结果中的intent值 |\n| session_state | 当前对话session中的state值 |\n| string | 字符串值，可以使用已定义变量进行模板填充 |\n\n特别的，开发者可以添加注册自定义函数，定义func_val类型的变量调用自定义函数实现功能扩展、定制化对话逻辑。DMKit默认内置提供了包括以下函数：\n\n| 函数名          |函数说明              | 参数  |\n|----------------|--------------|----------------------|\n| service_http_get                   | 通过HTTP GET的方式请求知识库、第三方API等服务，服务地址需配置于conf/app/remote_services.json中     |参数1：remote_services.json中配置的服务名 <br>参数2：服务请求的路径，例如\"/baidu/unit-dmkit\"    |\n| service_http_post                  | 通过HTTP POST的方式请求知识库、第三方API等服务，服务地址需配置于conf/app/remote_services.json中。注意：如果请求路径包含中文，需要先对中文进行URL编码后再拼接URL     |参数1：remote_services.json中配置的服务名 <br>参数2：服务请求的路径，例如\"/baidu/unit-dmkit\" <br>参数3：POST数据内容   |\n| json_get_value                     | 根据提供的路径从json字符串中获取对应的字段值       |参数1：json字符串 <br>参数2：所需获取的字段在json字符串中的路径。例如{\"data\":{\"str\":\"hello\", \"arr\":[{\"str\": \"world\"}]}}中路径data.str对应字段值为\"hello\", 路径data.arr.0.str对应字段值\"world\"。|\n| url_encode                         | 对输入字符串进行url编码操作       |参数1：进行编码的字符串|\n\n另外，DMKit默认定义提供以下变量：\n\n| 变量名                           | 说明                                                                      |\n|---------------------------------|--------------------------------------------------------------------------|\n| dmkit_param_last_tts            | 上一轮返回结果result中第一个type为tts的元素value值，如果不存在则为空字符串         |\n| dmkit_param_context_xxxxx       | 上一轮session结果context中key为xxxx的值，同时如果用户定义了名为dmkit_param_context_xxxxx的变量，dmkit自动将该变量以xxxxx为key存入本轮session结果context|\n| dmkit_param_slot_xxxxx          | qu结果中tag为xxxxx的slot值, 如果存在多个相同tag的slot，则取第一个|\n\n#### result中assertion类型说明：\n\n| type     |说明                                               |\n|----------|--------------------------------------------------|\n| empty    | value值为空                                       |\n| not_empty| value值非空                                       |\n| in       | value值以\",\"切分，第一个元素在从第二个元素开始的列表中   |\n| not_in   | value值以\",\"切分，第一个元素不在从第二个元素开始的列表中 |\n| eq       |  value值以\",\"切分，第一个元素等于第二个元素            |\n| gt       | value值以\",\"切分，第一个数字大于第二个数字             |\n| ge       | value值以\",\"切分，第一个数字大于等于第二个数字         |\n\n### 精简语法及可视化配置\n\n* 在默认基础配置之上，有能力的开发者可以自行设计使用更简洁的配置描述对话policy并转化为基础配置进行加载。\n* 对于多状态跳转的场景，可以引入了可视化的编辑工具，来描述对话跳转逻辑。这里我们提供了一个使用[mxgraph](https://github.com/jgraph/mxgraph)进行可视化配置的样例，文档参考：[可视化配置工具](visual_tool.md)\n\n## DMKit服务接口\n\n* DMKit服务监听端口及访问路径等参数可通过conf/gflags.conf文件进行配置，默认请求链接为http://<HOST>:8010/search, 其中<HOST>为DMKit服务所在机器IP，请求方式为POST\n* 服务接收POST数据协议与[UNIT2.0接口协议](http://ai.baidu.com/docs#/UNIT-v2-API/top)兼容。开发者按照协议组装JSON数据请求DMKit，DMKit按照该协议返回JSON数据，同时DMKit定义返回结果action_list中custom_reply类型为DM_RESULT时，返回内容为DMKit输出的output结果。\n"
  },
  {
    "path": "docs/visual_tool.md",
    "content": "# 对话流可视化配置\n\n针对状态繁多、跳转复杂的垂类，DMKit支持通过可视化编辑工具进行状态跳转流程的编辑设计，并同步转化为对话基础配置供对话管理引擎加载执行。\n\n## 基于开源可视化工具的配置样例\n\n这里的可视化编辑工具使用开源的[mxgraph](https://github.com/jgraph/mxgraph)可视化库，对话开发者可在可视化工具上进行图编辑，而该可视化库支持从图转化为xml文件，我们再利用转换框架实现对应的编译器将xml文件转化为对话基础配置加载执行。以demo场景【查询流量及续订】为例，步骤为：\n\n* 在[draw.io](https://www.draw.io/)中按照[编辑规则](#编辑规则)进行图编辑\n* 在编辑好的图导出为xml文件，放置于conf/app/demo目录下\n* 运行language_compiler/run.py程序，该程序调用对应的转换器将conf/app/demo目录下的xml文件转化为json文件\n* 将json文件注册于conf/app/products.json文件后，运行DMKit加载执行\n\n### 编辑规则\n\n规定使用以下构图元素进行编辑：\n\n* 单箭头连线，单箭头连线是路程图中最基本的元素之一，用来表示状态的跳转。注意在使用连线的时候，连线的两端需要出现蓝色的 x 标识，以确保这个连线成功连接了两个框。\n* 椭圆，用户节点，椭圆中存放的是用户的意图，以及槽位值（可选），内部语言格式为：\n    ```text\n    INTENT: intent_xxx\n    SLOT:user_a,user_b\n    ```\n该节点表示用户输入query的NLU解析结果，结合指向该节点的BOT节点，构成了DMKit基础配置中一个完成trigger条件\n\n* 圆角矩形，BOT节点，圆角矩形中存放的是BOT的回复，内部格式为：\n    ```text\n    PARAM:param_type:param_name1=param_value2\n    PARAM:param_type:param_name1=param_value2\n    BOT:XXXXXXX{%param_name1%}XXX{%param_name2%}\n    ```\n该节点表示BOT应该执行的回复，同时节点中可以定义参数并对回复进行模板填充。\n\n在这里定义`dmkit_param_context_xxxx`变量时，dmkit自动将该变量以`xxxx`为key存入本轮session结果context。下一轮可以定义type=session_context，value=xxxx的变量来读取，也可以直接使用value={%dmkit_param_context_xxxx%}来获取，具体可参考[params类型及说明](tutorial.md#params中变量类型列表及其说明) \n\n* 菱形，条件节点，在节点中可定义需要进行判断的变量:\n    ```text\n    PARAM:param_type:param_name1=param_value2\n    PARAM:param_type:param_name1=param_value2\n    ```\n    同时对该节点连出的单箭头连线可以添加描述跳转条件，条件可使用在菱形中定义的变量，例如：\n    ```text\n    ge:{%param1%},1\n    ```\n    跳转条件描述中，可用&&或||来连接多个条件以表达“和”或“或”，例如：\n    ```text\n    ge:{%param1%},1 || eq: {%param1%}, 10\n    ```\n    ||和&&不可同时出现在一个条件描述中。\n\n另外规定：\n\n* 一个椭圆仅可以连向一个圆角矩形或者一个菱形\n* 一个圆角矩形可以连向多个椭圆\n* 一个菱形可以连向多个圆角矩形\n\n详细使用示例参考conf/app/demo目录下demo场景的xml文件，该xml文件可在[draw.io](https://www.draw.io/)中导入查看\n"
  },
  {
    "path": "language_compiler/compiler_xml.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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\"\"\"\nParser for .xml file \n\n\"\"\"\nimport xml.etree.ElementTree as ET\nimport re \nimport codecs\nimport json\nimport sys\n\n\nclass Node(object):\n    \"\"\"\n    this class is used to denote the node in .xml file, which will be used in XmlParser\n    \"\"\"\n    def __init__(self, node_id, node_type, node_status, node_nlg, state, params):\n        self.node_id = node_id\n        self.node_type = node_type\n        self.node_status = node_status # intent for user node, empty for server node \n        self.node_nlg = node_nlg # slots for customer node, nlg for server node\n        self.state = state\n        self.from_nodes = [] # (node_type, node_id, arrow_value)\n        self.to_nodes = [] # (node_type, node_id, arrow_value)\n        self.params = params  # parameters for server node\n\n\nclass Arrow(object):\n    \"\"\"\n    this class is used to denote the arrow in .xml file, which will be used in XmlParser\n    \"\"\"\n    def __init__(self, arrow_source, arrow_target):\n        self.arrow_source = arrow_source # cell id \n        self.arrow_target = arrow_target # cell id \n        self.arrow_text = \"\"\n\n\nclass XmlParser(object):\n    \"\"\"\n    this class is used to represent the graph in .xml file as a class object, \n    all necessary information about the graph will be extracted from the .xml file.\n    \"\"\"\n    def __init__(self, xml_data):\n        # initialize the elementtree object\n        self.root = ET.fromstring(\"\".join(xml_data))\n\n        # collections of nodes, arrows, policies and nlg responses. \n        self.__nodes = {}\n        self.__arrows = {}\n        self.__nlgs = []\n        self.__user_nodes = []\n        self.__policies = []  # the output json\n\n        # methods to parse the element tree\n        self.__parse_cells() # parse every cell to extract info of node and arrow \n        self.__connect_nodes() # connect nodes with the info from arrow \n        self.__extract_policy()\n\n    def __clean_noise(self, value, stri='', noise=None):\n        if not noise:\n            noise = ['&nbsp;', '&nbsp', 'nbsp', '<br>', '<div>', '</div>', '<span>', '</span>', '<span lang=\"ZH-CN\">']\n        for n in noise:\n            value = value.replace(n, stri)\n        if not stri:\n            value = value.replace('&amp;', '&')\n        return value.strip()\n\n    def __clean_span(self, value, stri=''):\n        return self.__clean_noise(value, '', ['<span>', '</span>', '<span lang=\"ZH-CN\">'])\n\n    def __parse_cells(self):\n        todo_cells = []\n        state = 0\n        for cell in self.root[0]:\n            style = cell.get('style')\n            cell_id = cell.get('id')\n            # bot node \n            if style and style.startswith('rounded=1'):\n                value = cell.get('value') + '<'\n                value = self.__clean_span(value)\n                re_nlg = re.compile(r'BOT.*?<')\n                re_params = re.compile(r'PARAM.*?<')\n                re_state = re.compile(r'STATE.*?<')\n                nlgs = []\n                if re_nlg.findall(value): \n                    for n in re_nlg.findall(value):\n                        n = self.__clean_noise(n[4:-1])\n                        nlgs.append(n)\n                params = []\n                if re_params.findall(value):\n                    for p in re_params.findall(value):\n                        p = self.__clean_noise(p[6:-1])\n                        params.append(p)\n                node_state = None\n                if re_state.findall(value):\n                    for s in re_state.findall(value):\n                        node_state = self.__clean_noise(s[6:-1])\n                        break\n                if 'BOT' not in value:\n                    raise Exception('wrong shape is used in cell with text: ', nlg)                    \n                if value:\n                    if not node_state:\n                        state += 1\n                        node_state = (3 - len(str(state))) * '0' + str(state)\n                    node = Node(cell_id, 'server', '', nlgs, node_state, params)\n                    self.__nodes[cell_id] = node\n                continue\n            # customer node\n            if style and style.startswith('ellipse'):\n                value = cell.get('value') + '<'\n                value = self.__clean_span(value)\n                re_status = re.compile(r'INTENT.*?<')\n                status = re_status.findall(value)[0] \n                status = self.__clean_noise(status[status.find(':') + 1:-1])\n                re_nlg = re.compile(r'SLOT.*?<')\n                if re_nlg.findall(value):\n                    nlg = self.__clean_noise(re_nlg.findall(value)[0][5:-1])\n                else:\n                    nlg = \"\"\n                if 'INTENT' not in value:\n                    raise Exception('wrong shape is used in cell with text: ', nlg)  \n                if value:\n                    node = Node(cell_id, 'customer', status, nlg, '', [])\n                    self.__nodes[cell_id] = node\n                    self.__user_nodes.append(node)\n                continue \n            # arrow node\n            if cell.get('edge'):\n                source = cell.get('source')\n                target = cell.get('target')\n                text = cell.get('value')\n                if not target:\n                    raise Exception('some arrow is not pointing to anything')  \n                else:\n                    arrow = Arrow(source, target)\n                    if text:\n                        arrow.arrow_text = self.__clean_noise(text)\n                    self.__arrows[cell_id] = arrow\n                continue\n            # judge node\n            if style and style.startswith('rhombus'):\n                value = cell.get('value') + '<'\n                value = self.__clean_span(value)\n                re_params = re.compile(r'PARAM.*?<')\n                params = []\n                if re_params.findall(value):\n                    for p in re_params.findall(value):\n                        p = self.__clean_noise(p[6:-1])\n                        params.append(p)\n                if 'PARAM' not in value:\n                    raise Exception('wrong shape is used in cell with text: ', value)                    \n                if value:\n                    node = Node(cell_id, 'judge', '', '', '', params)\n                    self.__nodes[cell_id] = node \n                continue\n            todo_cells.append(cell)\n        # false initial\n        self.__false_initial = Node(-1, \"\", \"\", \"\", \"\", \"\")\n        self.__nodes[-1] = self.__false_initial \n\n        for cell in todo_cells:\n            style = cell.get('style')\n            parent_id = cell.get('parent')\n            value = cell.get('value')\n            if style and style.startswith('text'):\n                if parent_id in self.__arrows:\n                    self.__arrows[parent_id].arrow_text = self.__clean_noise(value)\n                else:\n                    raise Exception(\"there is a bad cell with text\", value)\n\n    def __connect_nodes(self):\n        for (arrow_id, arrow) in self.__arrows.items():\n            if not arrow.arrow_source:\n                source_node = self.__false_initial\n            else:\n                source_node = self.__nodes[arrow.arrow_source]\n            target_node = self.__nodes[arrow.arrow_target]\n            # update source node and target node \n            source_node.to_nodes.append((target_node.node_type, target_node.node_id, \n                        arrow.arrow_text))\n            self.__nodes[arrow.arrow_source] = source_node \n            target_node.from_nodes.append((source_node.node_type, \n                                           source_node.node_id, arrow.arrow_text))\n            self.__nodes[arrow.arrow_target] = target_node\n\n    def __extract_policy(self):\n        for node in self.__user_nodes:\n            intent = node.node_status\n            slots = node.node_nlg.replace(' ', '').split(',')\n            if slots[0] == \"\":\n                slots = []\n            params = []\n            output = []\n            if len(node.to_nodes) > 0:\n                dir_to_node_info = node.to_nodes[0]\n                dir_to_node = self.__nodes[dir_to_node_info[1]]\n                # points to one branch\n                if dir_to_node.node_type == \"server\":\n                    for p in dir_to_node.params:                        \n                        p = p.replace(\" \", \"\")\n                        c1 = p.find(\":\")\n                        c2 = p.find(\"=\")\n                        pname = p[c1 + 1:c2]                      \n                        ptype = p[0:c1]                        \n                        pvalue = p[c2 + 1:]                        \n                        param = {\"name\":pname, \"type\":ptype, \"value\":pvalue}\n                        params.append(param)\n                    next = {}\n                    next[\"assertion\"] = []\n                    next[\"session\"] = {\"state\": dir_to_node.state, \"context\": {}}\n                    results = []\n                    for n in dir_to_node.node_nlg:\n                        result = {}\n                        result[\"type\"] = \"tts\"\n                        alt = n.replace(\" \", \"\").split('|')\n                        if len(alt) == 1:\n                            result[\"value\"] = alt[0]\n                        else:\n                            result[\"value\"] = alt\n                        results.append(result)\n                    next[\"result\"] = results\n                    output.append(next)\n                # points to multiple branch\n                elif dir_to_node.node_type == \"judge\":\n                    # add params in judge nodes\n                    for p in dir_to_node.params:                        \n                        p = p.replace(\" \", \"\")\n                        c1 = p.find(\":\")\n                        c2 = p.find(\"=\")\n                        pname = p[c1 + 1:c2]                      \n                        ptype = p[0:c1]                        \n                        pvalue = p[c2 + 1:]\n                        param = {\"name\":pname, \"type\":ptype, \"value\":pvalue}\n                        params.append(param)\n                    # extract policies from bot nodes pointed to by the judge node\n                    for to_node_info in dir_to_node.to_nodes:\n                        to_node = self.__nodes[to_node_info[1]]\n                        nexts = []\n                        condition = to_node_info[2].replace(\" \", \"\")\n                        # A condition can contain either '&&'s or '||'s, but not both\n                        if '&&' in condition:\n                            conditions = condition.split('&&')\n                            assertions = []\n                            for cond in conditions:\n                                cut = cond.find(\":\")\n                                assertion = {}\n                                assertion[\"type\"] = cond[0:cut]\n                                assertion[\"value\"] = cond[cut + 1:]\n                                assertions.append(assertion)\n                            next = {}\n                            next[\"assertion\"] = assertions\n                            next[\"session\"] = {\"state\": to_node.state, \"context\": {}}\n                            nexts.append(next)\n                        elif '||' in condition:\n                            conditions = condition.split('||')\n                            for cond in conditions:\n                                next = {}\n                                assertion = {}\n                                cut = cond.find(\":\")\n                                assertion[\"type\"] = cond[0:cut]\n                                assertion[\"value\"] = cond[cut + 1:]\n                                next[\"assertion\"] = [assertion]\n                                next[\"session\"] = {\"state\": to_node.state, \"context\": {}}\n                                nexts.append(next)\n                        else:\n                            assertion = {}\n                            cut = condition.find(\":\")\n                            assertion[\"type\"] = condition[0:cut]\n                            assertion[\"value\"] = condition[cut + 1:]\n                            next = {}\n                            next[\"assertion\"] = [assertion]\n                            next[\"session\"] = {\"state\": to_node.state, \"context\": {}}\n                            nexts.append(next)\n\n                        results = []\n                        for n in to_node.node_nlg:\n                            result = {}\n                            result[\"type\"] = \"tts\"\n                            alt = n.replace(\" \", \"\").split('|')\n                            if len(alt) == 1:\n                                result[\"value\"] = alt[0]\n                            else:\n                                result[\"value\"] = alt\n                            results.append(result)\n                        for nxt in nexts:\n                            nxt[\"result\"] = results\n                            output.append(nxt)\n                        for p in to_node.params:                        \n                            p = p.replace(\" \", \"\")\n                            c1 = p.find(\":\")\n                            c2 = p.find(\"=\")\n                            pname = p[c1 + 1:c2]                      \n                            ptype = p[0:c1]                        \n                            pvalue = p[c2 + 1:]                        \n                            param = {\"name\":pname, \"type\":ptype, \"value\":pvalue}\n                            # merge\n                            if param not in params:\n                                params.append(param)\n\n            for from_node_info in node.from_nodes:\n                if from_node_info:\n                    policy = {}\n                    from_node = self.__nodes[from_node_info[1]]\n                    trigger = {}\n                    trigger[\"intent\"] = intent\n                    trigger[\"slots\"] = slots \n                    trigger[\"state\"] = from_node.state\n                    policy[\"trigger\"] = trigger\n                    policy[\"params\"] = params\n                    policy[\"output\"] = output\n                    self.__policies.append(policy)\n\n    def write_json(self):\n        \"\"\"\n        this method is used to return the parsed json for the .xml input\n        \"\"\"\n        return [json.dumps(self.__policies, ensure_ascii=False,\\\n                indent=2, sort_keys=True).encode('utf8')]\n\n\ndef run(data):\n    \"\"\"\n    runs the parser and returns the parsed json\n    \"\"\"\n    ps = XmlParser(data)\n    return ps.write_json()\n"
  },
  {
    "path": "language_compiler/run.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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\"\"\"\nCompiler Executor.\n\n\"\"\"\n\nimport codecs\nimport ConfigParser\nimport importlib\nimport os\nimport sys\n\n\ndef main():\n    \"\"\"\n    Compiler Executor\n    process files in data_path and generate system json configuration file\n\n    \"\"\"\n    current_dir = os.path.dirname(os.path.abspath(__file__))\n    sys.path.append(os.path.dirname(os.path.abspath(__file__)))\n\n    config = ConfigParser.ConfigParser()\n    config.read(current_dir + \"/settings.cfg\")\n    \n    compile_types = config.get('compiler', 'compile_types')\n    compile_types = compile_types.replace(' ', '').split(',')\n\n    data_path = current_dir + '/' + config.get('data', 'data_path')\n    for dirpath, dirnames, filenames in os.walk(data_path):\n        for filename in filenames:\n            filepath = os.path.join(dirpath, filename)\n            fname, extension = os.path.splitext(filename)\n            extension = extension[1:]\n            if extension not in compile_types:\n                continue\n            input_lines = []\n            with open(filepath, 'r') as f:\n                input_lines = f.readlines()\n            compiler_module = importlib.import_module('compiler_' + extension)\n            compiler_function = getattr(compiler_module, 'run')\n            output_lines = compiler_function(input_lines)\n            with open(os.path.join(dirpath, fname + \".json\"), 'w') as f:\n                for line in output_lines:\n                    f.write(\"%s\\n\" % line)\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "language_compiler/settings.cfg",
    "content": "[data]\ndata_path=../conf/app\n\n[compiler]\ncompile_types=xml\nexclude_file=\n\n\n"
  },
  {
    "path": "proto/http.proto",
    "content": "syntax=\"proto2\";\npackage dmkit;\n\noption cc_generic_services = true;\n\nmessage HttpRequest { };\nmessage HttpResponse { };\n\nservice HttpService {\n  rpc run(HttpRequest) returns (HttpResponse);\n};\n"
  },
  {
    "path": "src/app_container.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"app_container.h\"\n#include <chrono>\n#include \"app_log.h\"\n#include \"brpc.h\"\n#include \"dialog_manager.h\"\n\nnamespace dmkit {\n\nThreadLocalDataFactory::ThreadLocalDataFactory(ApplicationBase* application) {\n    this->_application = application;\n}\n\nThreadLocalDataFactory::~ThreadLocalDataFactory() {\n    this->_application = nullptr;\n}\n\nvoid* ThreadLocalDataFactory::CreateData() const {\n    return this->_application->create_thread_data();\n}\n\nvoid ThreadLocalDataFactory::DestroyData(void* d) const {\n    this->_application->destroy_thread_data(d);\n}\n\nAppContainer::AppContainer() {\n    this->_application = nullptr;\n    this->_data_factory = nullptr;\n}\n\nAppContainer::~AppContainer() {\n    delete this->_application;\n    this->_application = nullptr;\n\n    delete this->_data_factory;\n    this->_data_factory = nullptr;\n}\n\nint AppContainer::load_application() {\n    if (nullptr != this->_application) {\n        APP_LOG(ERROR) << \"an application has already be loaded\";\n        return -1;\n    }\n\n    // The real application is created here\n    this->_application = new DialogManager();\n\n    if (nullptr == this->_application || 0 != this->_application->init()) {\n        APP_LOG(ERROR) << \"failed to init application!!!\";\n        return -1;\n    }\n\n    this->_data_factory = new ThreadLocalDataFactory(this->_application);\n\n    return 0;\n}\n\nThreadLocalDataFactory* AppContainer::get_thread_local_data_factory() {\n    if (nullptr == this->_data_factory) {\n        APP_LOG(ERROR) << \"Data factory has not been initialized!!!\";\n        return nullptr;\n    }\n\n    return this->_data_factory;\n}\n\nint AppContainer::run(BRPC_NAMESPACE::Controller* cntl) {\n    if (nullptr == this->_application) {\n        APP_LOG(ERROR) << \"No application is not loaded for processing!!!\";\n        return -1;\n    }\n\n    auto time_start = std::chrono::steady_clock::now();\n\n    // Need to reset thread data status before running the application\n    ThreadDataBase* tls = static_cast<ThreadDataBase*>(BRPC_NAMESPACE::thread_local_data());\n    tls->reset();\n    APP_LOG(TRACE) << \"Running application\";\n    int result = this->_application->run(cntl);\n\n    auto time_end = std::chrono::steady_clock::now();\n    std::chrono::duration<double> diff = std::chrono::duration_cast<std::chrono::duration<double>>(time_end - time_start);\n    double total_cost = diff.count() * 1000;\n    APP_LOG(TRACE) << \"Application run cost(ms): \" << total_cost;\n    tls->add_notice_log(\"tm\", std::to_string(total_cost));\n    APP_LOG(NOTICE) << tls->get_notice_log();\n\n    return result;\n}\n\n} // namespace dmkit\n\n"
  },
  {
    "path": "src/app_container.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_APP_CONTAINER_H\n#define DMKIT_APP_CONTAINER_H\n\n#include \"application_base.h\"\n#include \"brpc.h\"\n\nnamespace dmkit {\n\nclass ThreadLocalDataFactory : public BRPC_NAMESPACE::DataFactory {\npublic:\n    ThreadLocalDataFactory(ApplicationBase* application);\n    ~ThreadLocalDataFactory();\n    void* CreateData() const;\n    void DestroyData(void* d) const;\n\nprivate:\n    ApplicationBase* _application;\n};\n\n// Container class which manages the instances of application,\n// as well as a thread data factory instance.\nclass AppContainer {\npublic:\n    AppContainer();\n    ~AppContainer();\n    int load_application();\n    ThreadLocalDataFactory* get_thread_local_data_factory();\n    int run(BRPC_NAMESPACE::Controller* cntl);\n\nprivate:\n    // The application instance is shared for all rpc threads\n    ApplicationBase* _application;\n\n    ThreadLocalDataFactory* _data_factory;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_APP_CONTAINER_H\n"
  },
  {
    "path": "src/app_log.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_APP_LOG_H\n#define DMKIT_APP_LOG_H\n\n#include \"brpc.h\"\n#include \"butil.h\"\n#include \"thread_data_base.h\"\n\nnamespace dmkit {\n\n// Wrapper for application logging to include trace id for each log during a request.\n#define APP_LOG(severity)  \\\n    LOG(severity) << \"logid=\" << (BRPC_NAMESPACE::thread_local_data() == nullptr ? \"\" : \\\n      (static_cast<dmkit::ThreadDataBase*>(BRPC_NAMESPACE::thread_local_data()))->get_log_id()) \\\n      << \" \"\n\n} // namespace dmkit\n\n#endif  //DMKIT_APP_LOG_H\n"
  },
  {
    "path": "src/application_base.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_APPLICATION_BASE_H\n#define DMKIT_APPLICATION_BASE_H\n\n#include \"brpc.h\"\n#include \"thread_data_base.h\"\n\nnamespace dmkit {\n\n// Base class for applications\n// Notice that the same application instance will be used for all request thread,\n// This call should be thread safe.\nclass ApplicationBase {\npublic:\n    ApplicationBase() {};\n    virtual ~ApplicationBase() {};\n\n    // Interface for application to do global initialization.\n    // This method will be invoke only once when server starts.\n    virtual int init() = 0;\n\n    // Interface for application to handle requests, it should be thread safe.\n    virtual int run(BRPC_NAMESPACE::Controller* cntl) = 0;\n\n    // Interface for application to register customized thread data.\n    virtual void* create_thread_data() const {\n        return new ThreadDataBase();\n    }\n\n    // Interface to destroy thread data, the data instance was created by create_thread_data.\n    virtual void destroy_thread_data(void* d) const {\n        delete static_cast<ThreadDataBase*>(d);\n    }\n\n    // Set log id for current request,\n    // application should set log id as early as possible when processing request\n    virtual void set_log_id(const std::string& log_id) {\n        ThreadDataBase* tls = static_cast<ThreadDataBase*>(BRPC_NAMESPACE::thread_local_data());\n        tls->set_log_id(log_id);\n    }\n\n    // Add a key/value notice log which will be logged when finish processing request\n    virtual void add_notice_log(const std::string& key, const std::string& value) {\n        ThreadDataBase* tls = static_cast<ThreadDataBase*>(BRPC_NAMESPACE::thread_local_data());\n        tls->add_notice_log(key, value);\n    }\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_APPLICATION_BASE_H\n\n"
  },
  {
    "path": "src/brpc.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_BRPC_H\n#define DMKIT_BRPC_H\n\n#ifndef BRPC_INCLUDE_PREFIX\n#define BRPC_INCLUDE_PREFIX <brpc\n#endif\n\n#ifndef BRPC_NAMESPACE\n#define BRPC_NAMESPACE brpc\n#endif\n\n#include BRPC_INCLUDE_PREFIX/data_factory.h>\n#include BRPC_INCLUDE_PREFIX/channel.h>\n#include BRPC_INCLUDE_PREFIX/controller.h>\n#include BRPC_INCLUDE_PREFIX/restful.h>\n#include BRPC_INCLUDE_PREFIX/server.h>\n\n#endif  //DMKIT_BRPC_H\n"
  },
  {
    "path": "src/butil.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_BUTIL_H\n#define DMKIT_BUTIL_H\n\n#ifndef BUTIL_INCLUDE_PREFIX\n#define BUTIL_INCLUDE_PREFIX <butil\n#endif\n\n#ifndef BUTIL_NAMESPACE\n#define BUTIL_NAMESPACE butil\n#endif\n\n#include BUTIL_INCLUDE_PREFIX/iobuf.h>\n#ifdef BUTIL_ENABLE_COMLOG_SINK\n#include BUTIL_INCLUDE_PREFIX/comlog_sink.h>\n#endif\n#include BUTIL_INCLUDE_PREFIX/containers/flat_map.h>\n#include BUTIL_INCLUDE_PREFIX/logging.h>\n\n#endif  //DMKIT_BUTIL_H\n"
  },
  {
    "path": "src/dialog_manager.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"dialog_manager.h\"\n#include <memory>\n#include <string>\n#include \"app_log.h\"\n#include \"butil.h\"\n#include \"rapidjson.h\"\n#include \"request_context.h\"\n#include \"utils.h\"\n\nnamespace dmkit {\n\nDialogManager::DialogManager() {\n    this->_remote_service_manager = new RemoteServiceManager();\n    this->_policy_manager = new PolicyManager();\n    this->_token_manager = new TokenManager();\n}\n\nDialogManager::~DialogManager() {\n    delete this->_policy_manager;\n    this->_policy_manager = nullptr;\n    delete this->_remote_service_manager;\n    this->_remote_service_manager = nullptr;\n    delete this->_token_manager;\n    this->_token_manager = nullptr;\n}\n\nint DialogManager::init() {\n    if (0 != this->_remote_service_manager->init(\"conf/app\", \"remote_services.json\")) {\n        APP_LOG(ERROR) << \"Failed to init _remote_service_manager\";\n        return -1;\n    }\n    APP_LOG(TRACE) << \"_remote_service_manager init done\";\n\n    if (0 != this->_policy_manager->init(\"conf/app\", \"products.json\")) {\n        APP_LOG(ERROR) << \"Failed to init _policy_manager\";\n        return -1;\n    }\n\n    if (0 != this->_token_manager->init(\"conf/app\", \"bot_tokens.json\")) {\n        APP_LOG(ERROR) << \"Failed to init _token_manager\";\n        return -1;\n    }\n    APP_LOG(TRACE) << \"_policy_manager init done\";\n\n    return 0;\n}\n\nint DialogManager::run(BRPC_NAMESPACE::Controller* cntl) {\n    std::string request_json = cntl->request_attachment().to_string();\n    APP_LOG(TRACE) << \"received request: \" << request_json;\n    this->add_notice_log(\"req\", request_json);\n\n    rapidjson::Document request_doc;\n    // In the case we cannot parse the request json, it is not a valid request.\n    if (request_doc.Parse(request_json.c_str()).HasParseError() || !request_doc.IsObject()) {\n        APP_LOG(WARNING) << \"Failed to parse request data to json\";\n        cntl->http_response().set_status_code(400);\n        return 0;\n    }\n\n    // Need to set log_id as soon as we can get it to avoid missing log_id in logs.\n    if (!request_doc.HasMember(\"log_id\") || !request_doc[\"log_id\"].IsString()) {\n        APP_LOG(WARNING) << \"Missing log_id\";\n        this->send_json_response(cntl, this->get_error_response(-1, \"Missing log_id\"));\n        return 0;\n    }\n    std::string log_id = request_doc[\"log_id\"].GetString();\n    std::string dmkit_log_id_prefix = \"dmkit_\";\n    log_id = dmkit_log_id_prefix + log_id;\n    this->set_log_id(log_id);\n    request_doc[\"log_id\"].SetString(log_id.c_str(), log_id.length(), request_doc.GetAllocator());\n\n    // Parsing bot_id from request json\n    if (!request_doc.HasMember(\"bot_id\") || !request_doc[\"bot_id\"].IsString()) {\n        APP_LOG(WARNING) << \"Missing bot_id\";\n        this->send_json_response(cntl, this->get_error_response(-1, \"Missing bot_id\"));\n        return 0;\n    }\n    std::string bot_id = request_doc[\"bot_id\"].GetString();\n\n    if (!request_doc.HasMember(\"request\") || !request_doc[\"request\"].HasMember(\"query\")\n            || !request_doc[\"request\"][\"query\"].IsString()) {\n        APP_LOG(WARNING) << \"Missing query\";\n        this->send_json_response(cntl, this->get_error_response(-1, \"Missing query\"));\n        return 0;\n    }\n    std::string query = request_doc[\"request\"][\"query\"].GetString();\n    std::string rewrite_query;\n    if (request_doc[\"request\"].HasMember(\"rewrite_query\") \n            && request_doc[\"request\"][\"rewrite_query\"].IsString()) {\n        rewrite_query = request_doc[\"request\"][\"rewrite_query\"].GetString();\n        request_doc[\"request\"].RemoveMember(\"rewrite_query\");\n    }\n\n    // Get dmkit session from request. We saved it in the bot session in latest response.\n    std::string dm_session;\n    if (request_doc.HasMember(\"bot_session\")) {\n        std::string request_bot_session = request_doc[\"bot_session\"].GetString();\n        rapidjson::Document request_bot_session_doc;\n        if (request_bot_session.empty()\n                || request_bot_session_doc.Parse(request_bot_session.c_str()).HasParseError()\n                || !request_bot_session_doc.IsObject()\n                || !request_bot_session_doc.HasMember(\"bot_id\")\n                || !request_bot_session_doc[\"bot_id\"].IsString()\n                || request_bot_session_doc[\"bot_id\"].GetString() != bot_id\n                || !request_bot_session_doc.HasMember(\"session_id\")\n                || !request_bot_session_doc.HasMember(\"dialog_state\")\n                || !request_bot_session_doc[\"dialog_state\"].HasMember(\"contexts\")\n                || !request_bot_session_doc[\"dialog_state\"][\"contexts\"].HasMember(\"dmkit\")\n                || !request_bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].HasMember(\"session\")) {\n            // Not a valid session from DMKit\n            request_doc[\"bot_session\"].SetString(\"\", 0, request_doc.GetAllocator());\n        } else {\n            dm_session =\n                request_bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"][\"session\"].GetString();\n        }\n    }\n    APP_LOG(TRACE) << \"dm session: \" << dm_session;\n    PolicyOutputSession session = PolicyOutputSession::from_json_str(dm_session);\n\n    // Get access_token from request uri.\n    std::string access_token;\n    const std::string* access_token_ptr = cntl->http_request().uri().GetQuery(\"access_token\");\n    if (access_token_ptr != nullptr) {\n        access_token = *access_token_ptr;\n    }\n    if (access_token.empty() && this->_token_manager->get_access_token(\n                bot_id, this->_remote_service_manager, access_token) != 0) {\n        APP_LOG(ERROR) << \"Failed to get access token\";\n        this->send_json_response(cntl, this->get_error_response(-1, \"Failed to get access token\"));\n        return 0;\n    }\n\n    std::string query_response;\n    bool is_dmkit_response = false;\n    this->process_request(request_doc, dm_session, access_token, query_response, is_dmkit_response);\n    if (is_dmkit_response || rewrite_query.empty()) {\n        this->send_json_response(cntl, query_response);\n        return 0;\n    }\n    std::string rewrite_query_response;\n    request_doc[\"request\"][\"query\"].SetString(rewrite_query.c_str(), \n        rewrite_query.length(), request_doc.GetAllocator());\n    this->process_request(request_doc, dm_session, access_token, \n        rewrite_query_response, is_dmkit_response);\n    if (is_dmkit_response) {\n        this->send_json_response(cntl, rewrite_query_response);\n        return 0;\n    }\n    this->send_json_response(cntl, query_response);\n    return 0;\n}\n\nint DialogManager::process_request(const rapidjson::Document& request_doc,\n                                   const std::string& dm_session,\n                                   const std::string& access_token,\n                                   std::string& json_response,\n                                   bool& is_dmkit_response) {\n    std::string bot_id = request_doc[\"bot_id\"].GetString();\n    std::string log_id = request_doc[\"log_id\"].GetString();\n    std::string query = request_doc[\"request\"][\"query\"].GetString();\n    is_dmkit_response = false;\n    std::string request_json = utils::json_to_string(request_doc);\n    // Call unit bot api with the request json as dmkit use the same data contract.\n    std::string unit_bot_result;\n    if (this->call_unit_bot(access_token, request_json, unit_bot_result) != 0) {\n        APP_LOG(ERROR) << \"Failed to call unit bot api\";\n        json_response = get_error_response(-1, \"Failed to call unit bot api\");\n        return 0;\n    }\n    APP_LOG(TRACE) << \"unit bot result: \" << unit_bot_result;\n\n    // Parse unit bot response.\n    // In the case something wrong with unit bot response, informs users.\n    rapidjson::Document unit_response_doc;\n    if (unit_response_doc.Parse(unit_bot_result.c_str()).HasParseError()\n            || !unit_response_doc.IsObject()) {\n        APP_LOG(ERROR) << \"Failed to parse unit bot result: \" << unit_bot_result;\n        json_response = get_error_response(-1, \"Failed to parse unit bot result\");\n        return -1;\n    }\n    if (!unit_response_doc.HasMember(\"error_code\")\n            || !unit_response_doc[\"error_code\"].IsInt()\n            || unit_response_doc[\"error_code\"].GetInt() != 0) {\n        json_response = unit_bot_result;\n        return 0;\n    }\n\n    // The bot status is included in bot_session\n    std::string bot_session = unit_response_doc[\"result\"][\"bot_session\"].GetString();\n    rapidjson::Document bot_session_doc;\n    if (bot_session_doc.Parse(bot_session.c_str()).HasParseError()\n            || !bot_session_doc.IsObject()) {\n        APP_LOG(ERROR) << \"Failed to parse bot session: \" << bot_session;\n        json_response = get_error_response(-1, \"Failed to parse bot session\");\n        return 0;\n    }\n    if (this->handle_unsatisfied_intent(unit_response_doc, \n            bot_session_doc, dm_session, json_response) == 0) {\n        return 0;\n    }\n\n    // Handle satify/understood intents\n    QuResult* qu_result = QuResult::parse_from_dialog_state(\n        bot_id, bot_session_doc[\"dialog_state\"]);\n    if (qu_result == nullptr) {\n        json_response = this->get_error_response(-1, \"Failed to parse qu_result\");\n        return 0;\n    }\n    auto qu_map = new BUTIL_NAMESPACE::FlatMap<std::string, QuResult*>();\n    // 2: bucket_count, initial count of buckets, big enough to avoid resize.\n    // 50: load_factor, element_count * 100 / bucket_count.\n    qu_map->init(2, 50);\n    qu_map->insert(bot_id, qu_result);\n    // Parsing request params from client_session, only string value is accepted\n    std::unordered_map<std::string, std::string> request_params;\n    std::string product = \"default\";\n    if (request_doc[\"request\"].HasMember(\"client_session\")) {\n        std::string client_session = request_doc[\"request\"][\"client_session\"].GetString();\n        rapidjson::Document client_session_doc;\n        if (!client_session_doc.Parse(client_session.c_str()).HasParseError() && client_session_doc.IsObject()) {\n            for (auto& m_param: client_session_doc.GetObject()) {\n                if (!m_param.value.IsString()) {\n                    continue;\n                }\n                std::string param_name = m_param.name.GetString();\n                std::string param_value = m_param.value.GetString();\n                if (param_name == \"product\") {\n                    product = param_value;\n                }\n                request_params[param_name] = param_value;\n            }\n        }\n    }\n    PolicyOutputSession session = PolicyOutputSession::from_json_str(dm_session);\n    RequestContext context(this->_remote_service_manager, log_id, request_params);\n    PolicyOutput* policy_output = this->_policy_manager->resolve(\n        product, qu_map, session, context);\n    for (auto iter = qu_map->begin(); iter != qu_map->end(); ++iter) {\n        QuResult* qu_ptr = iter->second;\n        if (qu_ptr != nullptr) {\n            delete qu_ptr;\n        }\n    }\n    delete qu_map;\n\n    if (policy_output == nullptr) {\n        json_response = this->get_error_response(-1, \"DM policy resolve failed\");\n        return 0;\n    }\n    bool has_query = false;\n    for (auto const& meta: policy_output->meta) {\n        if (meta.key == \"query\") {\n            has_query = true;\n        }\n    }\n    if (!has_query) {\n        KVPair meta_query;\n        meta_query.key = \"query\";\n        meta_query.value = query;\n        policy_output->meta.push_back(meta_query);\n    }\n    this->set_dm_response(unit_response_doc, bot_session_doc, policy_output);\n    delete policy_output;\n    is_dmkit_response = true;\n    json_response = utils::json_to_string(unit_response_doc);\n    return 0;\n}\n\nint DialogManager::call_unit_bot(const std::string& access_token,\n                                         const std::string& payload,\n                                         std::string& result) {\n    std::string url = \"/rpc/2.0/unit/bot/chat?access_token=\";\n    url += access_token;\n    RemoteServiceParam rsp = {\n        url,\n        HTTP_METHOD_POST,\n        payload\n    };\n    RemoteServiceResult rsr;\n    APP_LOG(TRACE) << \"Calling unit bot service, url: \"<< url;\n    APP_LOG(TRACE) <<  payload;\n    // unit_bot is a remote service configured in conf/app/remote_services.json\n    if (this->_remote_service_manager->call(\"unit_bot\", rsp, rsr) !=0) {\n        APP_LOG(ERROR) << \"Failed to get unit bot result\" ;\n        return -1;\n    }\n    APP_LOG(TRACE) << \"Got unit bot result\";\n\n    result = rsr.result;\n\n    return 0;\n}\n\nint DialogManager::handle_unsatisfied_intent(rapidjson::Document& unit_response_doc,\n                                             rapidjson::Document& bot_session_doc,\n                                             const std::string& dm_session,\n                                             std::string& response) {\n    std::string action_type;\n    if (unit_response_doc.HasMember(\"result\")\n            && unit_response_doc[\"result\"].HasMember(\"response\")\n            && unit_response_doc[\"result\"][\"response\"].HasMember(\"action_list\")\n            && unit_response_doc[\"result\"][\"response\"][\"action_list\"].Size() > 0\n            && unit_response_doc[\"result\"][\"response\"][\"action_list\"][0].HasMember(\"type\")) {\n        action_type = unit_response_doc[\"result\"][\"response\"][\"action_list\"][0][\"type\"].GetString();\n    } else {\n        APP_LOG(WARNING) << \"Failed to parse action type from unit bot response: \"\n            << utils::json_to_string(unit_response_doc);\n    }\n\n    if (action_type == \"satisfy\") {\n        response = this->get_error_response(-1, \"Unsupported action type satisfy\");\n        return 0;\n    }\n    if (action_type != \"understood\") {\n        // DM session should be saved\n        rapidjson::Value dm_session_json;\n        dm_session_json.SetString(\n            dm_session.c_str(), dm_session.length(), bot_session_doc.GetAllocator());\n        if (!bot_session_doc.HasMember(\"dialog_state\")) {\n            rapidjson::Value dialog_state_json(rapidjson::kObjectType);\n            bot_session_doc.AddMember(\"dialog_state\", dialog_state_json, bot_session_doc.GetAllocator());\n        }\n        if (!bot_session_doc[\"dialog_state\"].HasMember(\"contexts\")) {\n            rapidjson::Value contexts_json(rapidjson::kObjectType);\n            bot_session_doc[\"dialog_state\"].AddMember(\"contexts\", contexts_json, bot_session_doc.GetAllocator());\n        }\n        if (!bot_session_doc[\"dialog_state\"][\"contexts\"].HasMember(\"dmkit\")) {\n            rapidjson::Value contexts_json(rapidjson::kObjectType);\n            bot_session_doc[\"dialog_state\"][\"contexts\"].AddMember(\"dmkit\", contexts_json, bot_session_doc.GetAllocator());\n        }\n        if (bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].HasMember(\"session\")) {\n            bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].RemoveMember(\"session\");\n        }\n\n        bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].AddMember(\n            \"session\", dm_session_json, bot_session_doc.GetAllocator());\n\n        std::string bot_session = utils::json_to_string(bot_session_doc);\n        //unit_response_doc.AddMember(\"debug\", bot_session_doc, unit_response_doc.GetAllocator());\n        unit_response_doc[\"result\"][\"bot_session\"].SetString(\n            bot_session.c_str(), bot_session.length(), unit_response_doc.GetAllocator());\n        response = utils::json_to_string(unit_response_doc);\n        return 0;\n    }\n\n    return -1;\n}\n\nvoid DialogManager::set_dm_response(rapidjson::Document& unit_response_doc,\n                                            rapidjson::Document& bot_session_doc,\n                                            const PolicyOutput* policy_output) {\n    std::string session_str = PolicyOutputSession::to_json_str(policy_output->session);\n    rapidjson::Value dm_session;\n    dm_session.SetString(session_str.c_str(), session_str.length(), bot_session_doc.GetAllocator());\n\n    \n    if (!bot_session_doc.HasMember(\"dialog_state\")) {\n        rapidjson::Value dialog_state_json(rapidjson::kObjectType);\n        bot_session_doc.AddMember(\"dialog_state\", dialog_state_json, bot_session_doc.GetAllocator());\n    }   \n    if (!bot_session_doc[\"dialog_state\"].HasMember(\"contexts\")) {\n        rapidjson::Value contexts_json(rapidjson::kObjectType);\n        bot_session_doc[\"dialog_state\"].AddMember(\"contexts\", contexts_json, bot_session_doc.GetAllocator());    \n    }\n    if (!bot_session_doc[\"dialog_state\"][\"contexts\"].HasMember(\"dmkit\")) {    \n        rapidjson::Value contexts_json(rapidjson::kObjectType);\n        bot_session_doc[\"dialog_state\"][\"contexts\"].AddMember(\"dmkit\", contexts_json, bot_session_doc.GetAllocator());\n    }\n    if (bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].HasMember(\"session\")) {\n        bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].RemoveMember(\"session\");    \n    }\n    bot_session_doc[\"dialog_state\"][\"contexts\"][\"dmkit\"].AddMember(\n        \"session\", dm_session, bot_session_doc.GetAllocator());\n    \n    // DMKit result as a custom reply\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    writer.StartObject();\n    writer.Key(\"event_name\");\n    writer.String(\"DM_RESULT\");\n    writer.Key(\"result\");\n    std::string policy_output_str = PolicyOutput::to_json_str(*policy_output);\n    writer.String(policy_output_str.c_str(), policy_output_str.length());\n    writer.EndObject();\n    std::string custom_reply = buffer.GetString();\n    APP_LOG(TRACE) << \"custom_reply: \" << custom_reply;\n\n    bot_session_doc[\"interactions\"][0][\"response\"][\"action_list\"][0][\"type\"] = \"event\";\n    bot_session_doc[\"interactions\"][0][\"response\"][\"action_list\"][0][\"say\"] = \"\";\n    bot_session_doc[\"interactions\"][0][\"response\"][\"action_list\"][0][\"custom_reply\"].SetString(\n        custom_reply.c_str(), custom_reply.length(), unit_response_doc.GetAllocator());\n\n    unit_response_doc[\"result\"][\"response\"][\"action_list\"][0][\"type\"] = \"event\";\n    unit_response_doc[\"result\"][\"response\"][\"action_list\"][0][\"say\"] = \"\";\n    unit_response_doc[\"result\"][\"response\"][\"action_list\"][0][\"custom_reply\"].SetString(\n        custom_reply.c_str(), custom_reply.length(), unit_response_doc.GetAllocator());\n\n    std::string bot_session = utils::json_to_string(bot_session_doc);\n    //unit_response_doc.AddMember(\"debug\", bot_session_doc, unit_response_doc.GetAllocator());\n    unit_response_doc[\"result\"][\"bot_session\"].SetString(\n        bot_session.c_str(), bot_session.length(), unit_response_doc.GetAllocator());\n}\n\nstd::string DialogManager::get_error_response(int error_code, const std::string& error_msg) {\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    writer.StartObject();\n    writer.Key(\"error_code\");\n    writer.Int(error_code);\n    writer.Key(\"error_msg\");\n    writer.String(error_msg.c_str(), error_msg.length());\n    writer.EndObject();\n\n    return buffer.GetString();\n}\n\nvoid DialogManager::send_json_response(BRPC_NAMESPACE::Controller* cntl,\n                                       const std::string& data) {\n    cntl->http_response().set_content_type(\"application/json;charset=UTF-8\");\n    this->add_notice_log(\"ret\", data);\n    cntl->response_attachment().append(data);\n}\n\n} // namespace dmkit\n\n"
  },
  {
    "path": "src/dialog_manager.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"application_base.h\"\n#include \"policy.h\"\n#include \"policy_manager.h\"\n#include \"qu_result.h\"\n#include \"rapidjson.h\"\n#include \"remote_service_manager.h\"\n#include \"token_manager.h\"\n\n#ifndef DMKIT_DIALOG_MANAGER_H\n#define DMKIT_DIALOG_MANAGER_H\n\nnamespace dmkit {\n\n// The Dialog Manager application\nclass DialogManager : public ApplicationBase {\npublic:\n    DialogManager();\n    virtual ~DialogManager();\n    virtual int init();\n    virtual int run(BRPC_NAMESPACE::Controller* cntl);\n\nprivate:\n    int process_request(const rapidjson::Document& request_doc,\n                        const std::string& dm_session,\n                        const std::string& access_token,\n                        std::string& json_response,\n                        bool& is_dmkit_response);\n\n    int call_unit_bot(const std::string& access_token,\n                      const std::string& payload,\n                      std::string& result);\n\n    int handle_unsatisfied_intent(rapidjson::Document& unit_response_doc,\n                                  rapidjson::Document& bot_session_doc,\n                                  const std::string& dm_session,\n                                  std::string& response);\n\n    std::string get_error_response(int error_code, const std::string& error_msg);\n\n    void send_json_response(BRPC_NAMESPACE::Controller* cntl, const std::string& data);\n\n    void set_dm_response(rapidjson::Document& unit_response_doc,\n                         rapidjson::Document& bot_session_doc,\n                         const PolicyOutput* policy_output);\n\n    RemoteServiceManager* _remote_service_manager;\n    PolicyManager* _policy_manager;\n    TokenManager* _token_manager;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_DIALOG_MANAGER_H\n"
  },
  {
    "path": "src/file_watcher.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"file_watcher.h\"\n#include <sys/time.h>\n#include <sys/stat.h>\n#include \"app_log.h\"\n#include \"utils.h\"\n\nnamespace dmkit {\n\nconst int FileWatcher::CHECK_INTERVAL_IN_MILLS;\n\nFileWatcher&  FileWatcher::get_instance() {\n    static FileWatcher instance;\n    return instance;\n}\n\nFileWatcher::FileWatcher() {\n}\n\nFileWatcher::~FileWatcher() {\n    this->_is_running = false;\n    if (this->_watcher_thread.joinable()) {\n        this->_watcher_thread.join();\n    }\n}\n\nstatic int get_file_last_modified_time(const std::string& file_path, std::string& mtime_str) {\n    struct stat f_stat;\n    if (stat(file_path.c_str(), &f_stat) != 0) {\n        LOG(WARNING) << \"Failed to get file modified time\" << file_path;\n        return -1;\n    }\n    mtime_str = ctime(&f_stat.st_mtime);\n    return 0;\n}\n\nint FileWatcher::register_file(const std::string file_path,\n                               FileChangeCallback cb,\n                               void* param,\n                               bool level_trigger) {\n    LOG(TRACE) << \"FileWatcher registering file \" << file_path;\n    std::string last_modified_time;\n    if (get_file_last_modified_time(file_path, last_modified_time) != 0) {\n        return -1;\n    }\n\n    FileStatus file_status = {file_path, last_modified_time, cb, param, level_trigger};\n    std::lock_guard<std::mutex> lock(this->_mutex);\n    this->_file_info[file_path] = file_status;\n    if (!this->_is_running) {\n        this->_is_running = true;\n        this->_watcher_thread = std::thread(&FileWatcher::watcher_thread_func, this);\n    }\n    return 0;\n}\n\nint FileWatcher::unregister_file(const std::string file_path) {\n    LOG(TRACE) << \"FileWatcher unregistering file \" << file_path;\n    std::lock_guard<std::mutex> lock(this->_mutex);\n    if (this->_file_info.erase(file_path) != 1) {\n        return -1;\n    }\n    if (this->_file_info.size() == 0\n        && this->_is_running\n        && this->_watcher_thread.joinable()) {\n        this->_is_running = false;\n        this->_watcher_thread.join();\n    }\n    return 0;\n}\n\nvoid FileWatcher::watcher_thread_func() {\n    LOG(TRACE) << \"Watcher thread starting...\";\n    while (this->_is_running) {\n        {\n            std::lock_guard<std::mutex> lock(this->_mutex);\n            for (const auto& file : this->_file_info) {\n                std::string last_modified_time;\n                get_file_last_modified_time(file.first, last_modified_time);\n                if (last_modified_time != file.second.last_modified_time) {\n                    LOG(TRACE) << \"File Changed. \" << file.first << \" modified time \" << last_modified_time;\n                    if (file.second.callback(file.second.param) == 0\n                            || !file.second.level_trigger) {\n                        if (this->_file_info.find(file.first) != this->_file_info.end()) {\n                            this->_file_info[file.first].last_modified_time = last_modified_time;\n                        }\n                    }\n                }\n            }\n        }\n        std::this_thread::sleep_for(std::chrono::milliseconds(FileWatcher::CHECK_INTERVAL_IN_MILLS));\n    }\n    LOG(TRACE) << \"Watcher thread stopping...\";\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/file_watcher.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_FILE_WATCHER_H\n#define DMKIT_FILE_WATCHER_H\n\n#include <atomic>\n#include <mutex>\n#include <thread>\n#include <string>\n#include <unordered_map>\n\nnamespace dmkit {\n\n// Callback function when file changed\ntypedef int (*FileChangeCallback)(void* param);\n\nstruct FileStatus {\n    std::string file_path;\n    std::string last_modified_time;\n    FileChangeCallback callback;\n    void* param;\n    bool level_trigger;\n};\n\n// A file watcher singleton implemention\nclass FileWatcher {\npublic:\n    static FileWatcher& get_instance();\n\n    int register_file(const std::string file_path,\n                      FileChangeCallback cb,\n                      void* param,\n                      bool level_trigger=false);\n\n    int unregister_file(const std::string file_path);\n\n    // Do not need copy constructor and assignment operator for a singleton class\n    FileWatcher(FileWatcher const&) = delete;\n    void operator=(FileWatcher const&) = delete;\nprivate:\n    FileWatcher();\n    virtual ~FileWatcher();\n\n    void watcher_thread_func();\n\n    std::mutex _mutex;\n    std::atomic<bool> _is_running;\n    std::thread _watcher_thread;\n    std::unordered_map<std::string, FileStatus> _file_info;\n    static const int CHECK_INTERVAL_IN_MILLS = 1000;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_FILE_WATCHER_H\n"
  },
  {
    "path": "src/policy.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"policy.h\"\n#include \"app_log.h\"\n#include \"utils.h\"\n\nnamespace dmkit {\n\nPolicy::Policy(const PolicyTrigger& trigger, \n               const std::vector<PolicyParam>& params, \n               const std::vector<PolicyOutput>& outputs)\n    : _trigger(trigger), _params(params), _outputs(outputs) {\n}\n\nconst PolicyTrigger& Policy::trigger() const {\n    return this->_trigger;\n}\n\nconst std::vector<PolicyParam>& Policy::params() const {\n    return this->_params;\n}\n\nconst std::vector<PolicyOutput>& Policy::outputs() const {\n    return this->_outputs;\n}\n\n// Parse a policy from json configuration.\n// A sample policy is as following:\n//    {\n//        \"trigger\": {\n//            \"intent\": \"INTENT_XXX\",\n//            \"slots\": [\n//                \"slot_1\",\n//                \"slot_2\"\n//            ],\n//            \"state\": \"001\"\n//        },\n//        \"params\": [\n//            {\n//                \"name\": \"param_name\", \n//                \"type\": \"slot_val\", \n//                \"value\": \"slot_tag\"\n//            }\n//        ],\n//        \"output\": [\n//            {\n//                \"assertion\": [\n//                    {\n//                        \"type\": \"eq\", \n//                        \"value\": \"1,{%param_name%}\"\n//                    }\n//                ],\n//                \"session\": {\n//                    \"state\": \"002\"\n//                    \"context\": {\n//                        \"key1\": \"value1\",\n//                        \"key2\": \"value2\"\n//                    }\n//                },\n//                \"meta\":{\n//                    \"key1\": \"value1\",\n//                    \"key2\": \"value2\"\n//                },\n//                \"result\": [\n//                    {\n//                        \"type\":\"tts\",\n//                        \"value\": \"Hello World\"\n//                    }\n//                ]\n//            }\n//        ]\n//    }\nPolicy* Policy::parse_from_json_value(const rapidjson::Value& value) {\n    if (!value.IsObject()) {\n        LOG(WARNING) << \"Failed to parse policy from json, not an object: \" << utils::json_to_string(value);\n        return nullptr;\n    }\n\n    if (!value.HasMember(\"trigger\") || !value[\"trigger\"].IsObject()\n            || !value[\"trigger\"].HasMember(\"intent\") || !value[\"trigger\"][\"intent\"].IsString()) {\n        LOG(WARNING) << \"Failed to parse policy from json, invalid trigger\";\n        return nullptr;\n    }\n    PolicyTrigger trigger;\n    trigger.intent = value[\"trigger\"][\"intent\"].GetString();\n    \n    if (value[\"trigger\"].HasMember(\"slots\") && value[\"trigger\"][\"slots\"].IsArray()) {\n        for (auto& v : value[\"trigger\"][\"slots\"].GetArray()) {\n            trigger.slots.push_back(v.GetString());\n        }\n    }\n    if (value[\"trigger\"].HasMember(\"state\") && value[\"trigger\"][\"state\"].IsString()) {\n        trigger.state = value[\"trigger\"][\"state\"].GetString();\n    }\n\n    std::vector<PolicyParam> params;\n    if (value.HasMember(\"params\") && value[\"params\"].IsArray()) {\n        for (auto& v : value[\"params\"].GetArray()) {\n            PolicyParam param;\n            param.name = v[\"name\"].GetString();\n            param.type = v[\"type\"].GetString();\n            param.value = v[\"value\"].GetString();\n            if (v.HasMember(\"required\") && v[\"required\"].IsBool()) {\n                param.required = v[\"required\"].GetBool();\n            } else {\n                param.required = false;\n            }\n            if (v.HasMember(\"default\") && v[\"default\"].IsString()) {\n                param.default_value = v[\"default\"].GetString();\n            }\n            params.push_back(param);\n        }\n    }\n    \n    std::vector<PolicyOutput> outputs;\n    if (value.HasMember(\"output\") && value[\"output\"].IsArray()) {\n        for (auto& v : value[\"output\"].GetArray()) {\n            PolicyOutput output;\n            if (v.HasMember(\"assertion\") && v[\"assertion\"].IsArray()) {\n                for (auto& v_assertion: v[\"assertion\"].GetArray()) {\n                    std::string assertion_type = v_assertion[\"type\"].GetString();\n                    std::string assertion_value = v_assertion[\"value\"].GetString();\n                    PolicyOutputAssertion assertion = {assertion_type, assertion_value};\n                    output.assertions.push_back(assertion);\n                }\n            }\n            if (v.HasMember(\"session\") && v[\"session\"].IsObject()) {\n                if (v[\"session\"].HasMember(\"state\") && v[\"session\"][\"state\"].IsString()) {\n                    output.session.state = v[\"session\"][\"state\"].GetString();\n                }\n                if (v[\"session\"].HasMember(\"context\") && v[\"session\"][\"context\"].IsObject()) {\n                    for (auto& m_context: v[\"session\"][\"context\"].GetObject()) {\n                        std::string context_key = m_context.name.GetString();\n                        std::string context_value = m_context.value.GetString();\n                        KVPair context = {context_key, context_value};\n                        output.session.context.push_back(context);\n                    }\n                }\n            }\n            if (v.HasMember(\"meta\") && v[\"meta\"].IsObject()) {\n                for (auto& m_meta: v[\"meta\"].GetObject()) {\n                    std::string meta_key = m_meta.name.GetString();\n                    std::string meta_value = m_meta.value.GetString();\n                    KVPair meta = {meta_key, meta_value};\n                    output.meta.push_back(meta);\n                }\n            }\n            for (auto& v_result : v[\"result\"].GetArray()) {\n                PolicyOutputResult result;\n                result.type = v_result[\"type\"].GetString();\n                if (v_result[\"value\"].IsString()) {\n                    result.values.push_back(v_result[\"value\"].GetString());\n                } else if (v_result[\"value\"].IsArray()) {\n                    for (auto& v_result_value : v_result[\"value\"].GetArray()) {\n                        result.values.push_back(v_result_value.GetString());\n                    }\n                }\n                if (v_result.HasMember(\"extra\") && v_result[\"extra\"].IsString()) {\n                    result.extra = v_result[\"extra\"].GetString();\n                }\n                output.results.push_back(result);\n            }\n\n            outputs.push_back(output);\n        }\n    }\n    \n    return new Policy(trigger, params, outputs);;\n}\n\nstd::string PolicyOutputSession::to_json_str(const PolicyOutputSession& session) {\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    writer.StartObject();\n    writer.Key(\"domain\");\n    writer.String(session.domain.c_str(), session.domain.length());\n    writer.Key(\"state\");\n    writer.String(session.state.c_str(), session.state.length());\n    writer.Key(\"context\");\n    writer.StartObject();\n    for (auto const& object: session.context) {\n        writer.Key(object.key.c_str(), object.key.length());\n        writer.String(object.value.c_str(), object.value.length());\n    }\n    writer.EndObject();\n    writer.EndObject();\n    return buffer.GetString();\n}\n\nPolicyOutputSession PolicyOutputSession::from_json_str(const std::string& json_str) {\n    PolicyOutputSession session;\n    rapidjson::Document session_doc;\n    if (session_doc.Parse(json_str.c_str()).HasParseError() || !session_doc.IsObject()) {\n        return session;\n    }\n    if (session_doc.HasMember(\"domain\")) {\n        session.domain = session_doc[\"domain\"].GetString();\n    }\n    if (session_doc.HasMember(\"state\")) {\n        session.state = session_doc[\"state\"].GetString();\n    }\n    if (!session_doc.HasMember(\"context\")) {\n        return session;\n    }\n    for (auto& m_object: session_doc[\"context\"].GetObject()) {\n        std::string context_key = m_object.name.GetString();\n        std::string context_value = m_object.value.GetString();\n        KVPair context = {context_key, context_value};\n        session.context.push_back(context);\n    }\n\n    return session;\n}\n\nstd::string PolicyOutput::to_json_str(const PolicyOutput& output) {\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    writer.StartObject();\n    writer.Key(\"meta\");\n    writer.StartObject();\n    for (auto const& meta: output.meta) {\n        writer.Key(meta.key.c_str(), meta.key.length());\n        writer.String(meta.value.c_str(), meta.value.length());\n    }\n    writer.EndObject();\n    writer.Key(\"result\");\n    writer.StartArray();\n    for (auto const& result: output.results) {\n        writer.StartObject();\n        writer.Key(\"type\");\n        writer.String(result.type.c_str(), result.type.length());\n        writer.Key(\"value\");\n        writer.String(result.values[0].c_str(), result.values[0].length());\n        if (!result.extra.empty()) {\n            rapidjson::Document extra_doc;\n            if (!extra_doc.Parse(result.extra.c_str()).HasParseError() && extra_doc.IsObject()) {\n                for (auto& v_extra: extra_doc.GetObject()) {\n                    std::string extra_key = v_extra.name.GetString();\n                    if (extra_key == \"type\" || extra_key == \"value\") {\n                        LOG(WARNING) << \"Unsupported extra key \" << extra_key;\n                    }\n                    if (v_extra.value.IsString()) {\n                        std::string extra_value = v_extra.value.GetString();\n                        writer.Key(extra_key.c_str());\n                        writer.String(extra_value.c_str(), extra_value.length());\n                    } else if (v_extra.value.IsBool()) {\n                        writer.Key(extra_key.c_str());\n                        writer.Bool(v_extra.value.GetBool());\n                    } else if (v_extra.value.IsInt()) {\n                        writer.Key(extra_key.c_str());\n                        writer.Int(v_extra.value.GetInt());\n                    } else if (v_extra.value.IsDouble()) {\n                        writer.Key(extra_key.c_str());\n                        writer.Double(v_extra.value.GetDouble());\n                    } else {\n                        LOG(WARNING) << \"Unknown extra value type \" << v_extra.value.GetType();\n                    }\n                }\n            } else {\n                LOG(WARNING) << \"Failed to parse result extra json: \" <<  result.extra;\n            }\n        }\n        writer.EndObject();\n    }\n    writer.EndArray();\n\n    writer.EndObject();\n    return buffer.GetString();\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/policy.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_POLICY_H\n#define DMKIT_POLICY_H\n\n#include <string>\n#include <vector>\n#include \"rapidjson.h\"\n\nnamespace dmkit {\n\nstruct KVPair {\n    std::string key;\n    std::string value;\n};\n\n// A trigger define the condition under which a policy is choosen,\n// including intent and slots from qu result, as well as the current dm state.\nstruct PolicyTrigger {\n    std::string intent;\n    std::vector<std::string> slots;\n    std::string state;\n};\n\n// The parameter required in a policy.\nstruct PolicyParam {\n    std::string name;\n    std::string type;\n    std::string value;\n    std::string default_value;\n    bool required;\n};\n\n// Session for policy output, including current domain, user defines contexts\n// and a state which DM will move to.\nstruct PolicyOutputSession {\n    std::string domain;\n    std::string state;\n    std::vector<KVPair> context;\n\n    static std::string to_json_str(const PolicyOutputSession& session);\n\n    static PolicyOutputSession from_json_str(const std::string& json_str);\n};\n\n// A result item of dm output.\nstruct PolicyOutputResult {\n    std::string type;\n    std::vector<std::string> values;\n    std::string extra;\n};\n\nstruct PolicyOutputQuSlot {\n    std::string key;\n    std::string value;\n    std::string normalized_value;\n};\n\n// In case the Qu result is required as well, currently not used.\nstruct PolicyOutputQu {\n    std::string domain;\n    std::string intent;\n    std::vector<PolicyOutputQuSlot> slots;\n};\n\n// An assertion defines the condition under which a result is choosen.\nstruct PolicyOutputAssertion {\n    std::string type;\n    std::string value;\n};\n\n// Schema for DMKit output\nstruct PolicyOutput {\n    std::vector<PolicyOutputAssertion> assertions;\n    PolicyOutputQu qu;\n    std::vector<KVPair> meta;\n    PolicyOutputSession session;\n    std::vector<PolicyOutputResult> results;\n\n    static std::string to_json_str(const PolicyOutput& output);\n};\n\n// A policy defines a processing(params) & response(output),\n// given a trigger(intent+slots+state) condition.\nclass Policy {\npublic:\n    Policy(const PolicyTrigger& trigger,\n           const std::vector<PolicyParam>& params, \n           const std::vector<PolicyOutput>& outputs);\n    const PolicyTrigger& trigger() const;\n    const std::vector<PolicyParam>& params() const;\n    const std::vector<PolicyOutput>& outputs() const;\n\n    static Policy* parse_from_json_value(const rapidjson::Value& value);\n\nprivate:\n    PolicyTrigger _trigger;\n    std::vector<PolicyParam> _params;\n    std::vector<PolicyOutput> _outputs;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_POLICY_H\n"
  },
  {
    "path": "src/policy_manager.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"policy_manager.h\"\n#include <ctime>\n#include <forward_list>\n#include <stdlib.h>\n#include <sys/time.h>\n#include <sys/stat.h>\n#include <unordered_set>\n#include <unordered_map>\n#include <unistd.h>\n#include <utility>\n#include \"app_log.h\"\n#include \"file_watcher.h\"\n#include \"utils.h\"\n\nnamespace dmkit {\n\nDomainPolicy::DomainPolicy(const std::string& name, int score, IntentPolicyMap* intent_policy_map)\n    : _name(name), _score(score), _intent_policy_map(intent_policy_map) {\n}\n\nDomainPolicy::~DomainPolicy() {\n    if (this->_intent_policy_map == nullptr) {\n        return;\n    }\n    for (IntentPolicyMap::iterator iter = this->_intent_policy_map->begin();\n            iter != this->_intent_policy_map->end(); ++iter) {\n        auto policy_vector = iter->second;\n        if (policy_vector == nullptr) {\n            continue;\n        }\n        for (PolicyVector::iterator iter2 = policy_vector->begin();\n                iter2 != policy_vector->end(); ++iter2) {\n            auto policy = *iter2;\n            if (policy == nullptr) {\n                continue;\n            }\n            delete policy;\n            *iter2 = nullptr;\n        }\n        delete policy_vector;\n        iter->second = nullptr;\n    }\n    delete this->_intent_policy_map;\n    this->_intent_policy_map = nullptr;\n}\n\nint DomainPolicy::score() {\n    return this->_score;\n}\n\nconst std::string& DomainPolicy::name() {\n    return this->_name;\n}\n\nIntentPolicyMap* DomainPolicy::intent_policy_map() {\n    return this->_intent_policy_map;\n}\n\nPolicyManager::PolicyManager() {\n    this->_user_function_manager = nullptr;\n}\n\nPolicyManager::~PolicyManager() {\n    if (this->_user_function_manager != nullptr) {\n        delete this->_user_function_manager;\n        this->_user_function_manager = nullptr;\n    }\n\n    FileWatcher::get_instance().unregister_file(this->_conf_file_path);\n    this->_p_policy_dict.reset();\n}\n\nstatic inline void destroy_policy_dict(ProductPolicyMap* policy_dict) {\n    LOG(TRACE) << \"Destroying policy dict\";\n    if (policy_dict == nullptr) {\n        return;\n    }\n    for (ProductPolicyMap::iterator iter = policy_dict->begin(); iter != policy_dict->end();\n         ++iter) {\n        auto domain_policy_map = iter->second;\n        if (domain_policy_map == nullptr) {\n            continue;\n        }\n        for (DomainPolicyMap::iterator iter2 = domain_policy_map->begin();\n             iter2 != domain_policy_map->end(); ++iter2) {\n            auto domain_policy = iter2->second;\n            if (domain_policy == nullptr) {\n                continue;\n            }\n            delete domain_policy;\n            iter2->second = nullptr;\n        }\n        delete domain_policy_map;\n        iter->second = nullptr;\n    }\n    delete policy_dict;\n    policy_dict = nullptr;\n}\n\n// Loads policies from JSON configuration files.\nint PolicyManager::init(const char* dir_path, const char* conf_file) {\n    std::string file_path;\n    if (dir_path != nullptr) {\n        file_path += dir_path;\n    }\n    if (!file_path.empty() && file_path[file_path.length() - 1] != '/') {\n        file_path += '/';\n    }\n    if (conf_file != nullptr) {\n        file_path += conf_file;\n    }\n    this->_conf_file_path = file_path;\n\n    ProductPolicyMap* policy_dict = this->load_policy_dict();\n    if (policy_dict == nullptr) {\n        APP_LOG(ERROR) << \"Failed to init policy dict\";\n        return -1;\n    }\n    this->_p_policy_dict.reset(policy_dict, [](ProductPolicyMap* p) { destroy_policy_dict(p); });\n    FileWatcher::get_instance().register_file(\n        this->_conf_file_path, PolicyManager::policy_conf_change_callback, this, true);\n\n    this->_user_function_manager = new UserFunctionManager();\n    if (this->_user_function_manager->init() != 0) {\n        APP_LOG(ERROR) << \"Failed to init UserFunctionManager\";\n        return -1;\n    }\n\n    return 0;\n}\n\nint PolicyManager::reload() {\n    LOG(TRACE) << \"Reloading policy dict\";\n    ProductPolicyMap * policy_dict = this->load_policy_dict();\n    if (policy_dict == nullptr) {\n        LOG(WARNING) << \"Cannot reload policy! Policy dict load failed.\";\n        return -1;\n    }\n\n    this->_p_policy_dict.reset(policy_dict, [](ProductPolicyMap* p) { destroy_policy_dict(p); });\n    APP_LOG(TRACE) << \"Reload finished.\";\n    return 0;\n}\n\nint PolicyManager::policy_conf_change_callback(void* param) {\n    PolicyManager* pm = (PolicyManager*)param;\n    return pm->reload();\n}\n\nPolicyOutput* PolicyManager::resolve(const std::string& product,\n                                     BUTIL_NAMESPACE::FlatMap<std::string, QuResult*>* qu_result,\n                                     const PolicyOutputSession& session,\n                                     const RequestContext& context) {\n    std::shared_ptr<ProductPolicyMap> p_policy_map(this->_p_policy_dict);\n    if (p_policy_map == nullptr) {\n        APP_LOG(ERROR) << \"Policy resolve failed, empty policy dict\";\n        return nullptr;\n    }\n\n    DomainPolicyMap** seek_result = p_policy_map->seek(product);\n    if (seek_result == nullptr) {\n        APP_LOG(WARNING) << \"unkown product \" << product;\n        return nullptr;\n    }\n\n    DomainPolicyMap* domain_policy_map = *seek_result;\n    DomainPolicy* state_domain_policy = nullptr;\n    Policy* state_policy = nullptr;\n    std::forward_list<std::pair<DomainPolicy*, Policy*>> ranked_policies;\n    std::vector<Slot> empty_slots;\n    QuResult empty_qu(\"\", \"\", empty_slots);\n    std::string request_domain;\n    context.try_get_param(\"domain\", request_domain);\n    for (DomainPolicyMap::iterator iter = domain_policy_map->begin();\n            iter != domain_policy_map->end(); ++iter) {\n        auto domain_policy = iter->second;\n        const std::string& domain_name = domain_policy->name();\n        if (!request_domain.empty() && domain_name != request_domain) {\n            continue;\n        }\n        QuResult** qu_seek_result = qu_result->seek(domain_name);\n        QuResult* qu = qu_seek_result != nullptr ? *qu_seek_result : &empty_qu;\n\n        // Find a best policy give the qu result in current domain\n        Policy* find_result = this->find_best_policy(domain_policy, qu, session, context);\n        if (find_result == nullptr) {\n            continue;\n        }\n\n        // Policy with a domain and trigger state matches current DMKit domain&state is ranked top\n        if (!session.domain.empty() && (domain_name == session.domain)\n            && !session.state.empty() && (find_result->trigger().state == session.state)) {\n            state_domain_policy = domain_policy;\n            state_policy = find_result;;\n            continue;\n        }\n\n        // In case there are multiple domain results, the policies a ranked by static domain score\n        auto previous_it = ranked_policies.before_begin();\n        for (auto it = ranked_policies.begin(); it != ranked_policies.end(); ++it) {\n            if (domain_policy->score() > it->first->score()) {\n                break;\n            }\n            previous_it = it;\n        }\n        std::pair<DomainPolicy*, Policy*> p(domain_policy, find_result);\n        ranked_policies.insert_after(previous_it, p);\n    }\n\n    if (state_domain_policy != nullptr && state_policy != nullptr) {\n        std::pair<DomainPolicy*, Policy*> p(state_domain_policy, state_policy);\n        ranked_policies.insert_after(ranked_policies.before_begin(), p);\n    }\n\n    // Resolve policy output and returns the first output resolved successfully.\n    for (auto& p: ranked_policies) {\n        const std::string& domain_name = p.first->name();\n        APP_LOG(TRACE) << \"Resolving policy output for domain [\" << domain_name << \"]\";\n        QuResult** qu_seek_result = qu_result->seek(domain_name);\n        QuResult* qu = qu_seek_result != nullptr ? *qu_seek_result : &empty_qu;\n        PolicyOutput* result = this->resolve_policy_output(domain_name,\n                p.second, qu, session, context);\n        if (result != nullptr) {\n            APP_LOG(TRACE) << \"Final result domain [\" << domain_name << \"]\";\n            return result;\n        }\n    }\n\n    return nullptr;\n}\n\nProductPolicyMap* PolicyManager::load_policy_dict() {\n    ProductPolicyMap* product_policy_map = new ProductPolicyMap();\n    // 10: bucket_count, initial count of buckets, big enough to avoid resize.\n    // 80: load_factor, element_count * 100 / bucket_count.\n    product_policy_map->init(10, 80);\n\n    FILE* fp = fopen(this->_conf_file_path.c_str(), \"r\");\n    if (fp == nullptr) {\n        APP_LOG(ERROR) << \"Failed to open file \" << this->_conf_file_path;\n        destroy_policy_dict(product_policy_map);\n        return nullptr;\n    }\n    char read_buffer[1024];\n    rapidjson::FileReadStream is(fp, read_buffer, sizeof(read_buffer));\n    rapidjson::Document doc;\n    doc.ParseStream(is);\n    fclose(fp);\n\n    if (doc.HasParseError() || !doc.IsObject()) {\n        APP_LOG(ERROR) << \"Failed to parse products.json file\";\n        destroy_policy_dict(product_policy_map);\n        return nullptr;\n    }\n\n    for (rapidjson::Value::ConstMemberIterator prod_iter = doc.MemberBegin();\n            prod_iter != doc.MemberEnd(); ++prod_iter) {\n        std::string prod_name = prod_iter->name.GetString();\n        if (!prod_iter->value.IsObject()) {\n            APP_LOG(ERROR) << \"Invalid product conf for \" << prod_name;\n            destroy_policy_dict(product_policy_map);\n            return nullptr;\n        }\n        DomainPolicyMap* domain_policy_map = this->load_domain_policy_map(prod_name, prod_iter->value);\n        if (domain_policy_map == nullptr) {\n            APP_LOG(ERROR) << \"Failed to load policies for product \" << prod_name;\n            destroy_policy_dict(product_policy_map);\n            return nullptr;\n        }\n        product_policy_map->insert(prod_name, domain_policy_map);\n    }\n\n    return product_policy_map;\n}\n\nDomainPolicyMap* PolicyManager::load_domain_policy_map(const std::string& product_name,\n                                                        const rapidjson::Value& product_json) {\n    DomainPolicyMap* domain_policy_map = new DomainPolicyMap();\n    // 10: bucket_count, initial count of buckets, big enough to avoid resize.\n    // 80: load_factor, element_count * 100 / bucket_count.\n    domain_policy_map->init(10, 80);\n\n    APP_LOG(TRACE) << \"Loading policies for product: \" << product_name;\n    for (rapidjson::Value::ConstMemberIterator domain_iter = product_json.MemberBegin();\n            domain_iter != product_json.MemberEnd(); ++domain_iter) {\n        std::string domain_name = domain_iter->name.GetString();\n        const rapidjson::Value& domain_json = domain_iter->value;\n        rapidjson::Value::ConstMemberIterator setting_iter;\n        setting_iter = domain_json.FindMember(\"score\");\n        if (setting_iter == domain_json.MemberEnd() || !setting_iter->value.IsInt()) {\n            APP_LOG(WARNING) << \"Failed to parse score for domain \"\n                << domain_name << \" in product \" << product_name << \", skipped\";\n            continue;\n        }\n        int score = setting_iter->value.GetInt();\n\n        setting_iter = domain_json.FindMember(\"conf_path\");\n        if (setting_iter == domain_json.MemberEnd() || !setting_iter->value.IsString()) {\n            APP_LOG(WARNING) << \"Failed to parse conf_path for domain \"\n                << domain_name << \" in product \" << product_name << \", skipped\";\n            continue;\n        }\n        std::string conf_path = setting_iter->value.GetString();\n\n        APP_LOG(TRACE) << \"Loading policies for domain \" << domain_name << \" from \" << conf_path;\n        DomainPolicy* domain_policy = this->load_domain_policy(domain_name, score, conf_path);\n        if (domain_policy == nullptr) {\n            APP_LOG(WARNING) << \"Failed to load policy for domain \"\n                << domain_name << \" in product \" << product_name << \", skipped\";\n            continue;\n        }\n        APP_LOG(TRACE) << \"Loaded policies for domain \" << domain_name;\n\n        domain_policy_map->insert(domain_name, domain_policy);\n    }\n\n    return domain_policy_map;\n}\n\nDomainPolicy* PolicyManager::load_domain_policy(const std::string& domain_name,\n                                                int score,\n                                                const std::string& conf_path) {\n    FILE* fp = fopen(conf_path.c_str(), \"r\");\n    if (fp == nullptr) {\n        APP_LOG(ERROR) << \"Failed to open file \" << conf_path;\n        return nullptr;\n    }\n    char read_buffer[1024];\n    rapidjson::FileReadStream is(fp, read_buffer, sizeof(read_buffer));\n    rapidjson::Document doc;\n    doc.ParseStream(is);\n    fclose(fp);\n    if (doc.HasParseError() || !doc.IsArray()) {\n        APP_LOG(ERROR) << \"Failed to parse domain conf \" << conf_path;\n        return nullptr;\n    }\n    IntentPolicyMap* intent_policy_map = new IntentPolicyMap();\n    // 10: bucket_count, initial count of buckets, big enough to avoid resize.\n    // 80: load_factor, element_count * 100 / bucket_count.\n    intent_policy_map->init(10, 80);\n    for (rapidjson::Value::ConstValueIterator policy_iter = doc.Begin();\n            policy_iter != doc.End(); ++policy_iter) {\n        APP_LOG(TRACE) << \"loading policy...\";\n        Policy* policy = Policy::parse_from_json_value(*policy_iter);\n        if (policy == nullptr) {\n            APP_LOG(WARNING) << \"Found invalid policy conf in path \" << conf_path << \", skipped\";\n            continue;\n        }\n        const std::string& trigger_intent = policy->trigger().intent;\n        if (intent_policy_map->seek(trigger_intent) == nullptr) {\n            intent_policy_map->insert(trigger_intent, new PolicyVector);\n        }\n        (*intent_policy_map)[trigger_intent]->push_back(policy);\n    }\n    APP_LOG(TRACE) << \"initializing domain policy...\";\n    DomainPolicy* domain_policy = new DomainPolicy(domain_name, score, intent_policy_map);\n    APP_LOG(TRACE) << \"finish initializing domain policy...\";\n    return domain_policy;\n}\n\n// When multiple policies satisfy the current intent,\n// the following strategy is applies to find the best one:\n// 1. The policies with none empty trigger state, it should match current DM state.\n// 2. Policy with maximum number of matched trigger slot is ranked top.\nstatic Policy* find_best_policy_from_candidates(PolicyVector& policy_vector,\n                                                std::string& state,\n                                                std::unordered_multiset<std::string>& qu_slot_set) {\n    Policy* policy_result = nullptr;\n    for (auto const& policy: policy_vector) {\n        if (!policy->trigger().state.empty() && policy->trigger().state != state) {\n            continue;\n        }\n\n        bool missing_slot = false;\n        std::unordered_multiset<std::string> trigger_slot_set;\n        for (auto const& slot: policy->trigger().slots) {\n            trigger_slot_set.insert(slot);\n        }\n        for (auto iter = trigger_slot_set.begin(); iter != trigger_slot_set.end();) {\n            int trigger_slot_cnt = trigger_slot_set.count(*iter);\n            int qu_slot_cnt = qu_slot_set.count(*iter);\n            if (qu_slot_cnt < trigger_slot_cnt) {\n                missing_slot = true;\n                break;\n            }\n            std::advance(iter, trigger_slot_cnt);\n        }\n        if (missing_slot) {\n            continue;\n        }\n\n        if (policy_result == nullptr) {\n            policy_result = policy;\n            continue;\n        }\n\n        if (!policy_result->trigger().state.empty() && policy->trigger().state.empty()) {\n            continue;\n        }\n\n        if (policy_result->trigger().state.empty() && !policy->trigger().state.empty()) {\n            policy_result = policy;\n            continue;\n        }\n\n        if (policy_result->trigger().slots.size() < policy->trigger().slots.size()) {\n            policy_result = policy;\n        }\n    }\n\n    return policy_result;\n}\n\nPolicy* PolicyManager::find_best_policy(DomainPolicy* domain_policy,\n                                        QuResult* qu_result,\n                                        const PolicyOutputSession& session,\n                                        const RequestContext& context) {\n    (void) context;\n\n    std::string state;\n    if (domain_policy->name() == session.domain) {\n        state = session.state;\n    }\n\n    std::unordered_multiset<std::string> qu_slot_set;\n    IntentPolicyMap* intent_policy_map = domain_policy->intent_policy_map();\n    PolicyVector** policy_vector_seek = nullptr;\n    Policy* policy_result = nullptr;\n\n    for (auto const& slot: qu_result->slots()) {\n        qu_slot_set.insert(slot.key());\n    }\n    // Policy with matching intent.\n    const std::string& intent = qu_result->intent();\n    policy_vector_seek = intent_policy_map->seek(intent);\n    if (policy_vector_seek != nullptr) {\n        APP_LOG(TRACE) << \"intent [\" << intent << \"] candidate count [\" << (*policy_vector_seek)->size() << \"]\";\n        policy_result = find_best_policy_from_candidates(**policy_vector_seek, state, qu_slot_set);\n    }\n\n    // Fallback policy when none of the policies match intent.\n    if (policy_result == nullptr) {\n        const std::string fallback_intent = \"dmkit_intent_fallback\";\n        policy_vector_seek = intent_policy_map->seek(fallback_intent);\n        if (policy_vector_seek != nullptr) {\n            APP_LOG(TRACE) << \"dmkit_intent_fallback candidate count [\" << (*policy_vector_seek)->size() << \"]\";\n            policy_result = find_best_policy_from_candidates(**policy_vector_seek, state, qu_slot_set);\n        }\n    }\n\n    return policy_result;\n}\n\n// Resolve a string with params in it.\nstatic bool try_resolve_params(std::string& unresolved,\n                              const std::unordered_map<std::string, std::string>& param_map) {\n\n    if (unresolved.empty()) {\n        return true;\n    }\n\n    std::string resolved;\n    bool is_param = false;\n    unsigned int last_index = 0;\n    for (unsigned int i = 0; i < unresolved.length(); ++i) {\n        if (unresolved[i] == '{' && i + 1 < unresolved.length() && unresolved[i + 1] == '%' ) {\n            resolved += unresolved.substr(last_index, i - last_index);\n            last_index = i + 2;\n            is_param = true;\n            ++i;\n        }\n        if (unresolved[i] == '%' && i + 1 < unresolved.length() && unresolved[i + 1] == '}') {\n            if (!is_param) {\n                APP_LOG(WARNING) << \"Cannot resolve params in string, invalid format. \" << unresolved;\n                return false;\n            }\n            std::string param_name = unresolved.substr(last_index, i - last_index);\n            std::unordered_map<std::string, std::string>::const_iterator find_res = param_map.find(param_name);\n            if (find_res == param_map.end()) {\n                APP_LOG(WARNING) << \"Cannot resolve params in string, unknow param. \"\n                    << unresolved << \" \" << param_name;\n                return false;\n            }\n            resolved += find_res->second;\n            last_index = i + 2;\n            is_param = false;\n            ++i;\n        }\n    }\n    if (is_param) {\n        APP_LOG(WARNING) << \"Cannot resolve params in string, invalid format. \" << unresolved;\n        return false;\n    }\n    if (last_index < unresolved.length()) {\n        resolved += unresolved.substr(last_index);\n    }\n\n    unresolved = resolved;\n    return true;\n}\n\n// Resolve a string with delimiter and params in it\nstatic bool try_resolve_param_list(const std::string& unresolved,\n                                   const char delimiter,\n                                   const std::unordered_map<std::string, std::string>& param_map,\n                                   std::vector<std::string> &result) {\n    std::size_t pos = 0;\n    std::size_t last_pos = 0;\n    result.clear();\n    while (last_pos < unresolved.length() && (pos = unresolved.find(delimiter, last_pos)) != std::string::npos) {\n        std::string part = unresolved.substr(last_pos, pos - last_pos);\n        utils::trim(part);\n        if (!try_resolve_params(part, param_map)) {\n            result.clear();\n            return false;\n        }\n        result.push_back(part);\n        last_pos = pos + 1;\n    }\n    if (last_pos < unresolved.length()) {\n        std::string part = unresolved.substr(last_pos);\n        utils::trim(part);\n        if (!try_resolve_params(part, param_map)) {\n            result.clear();\n            return false;\n        }\n        result.push_back(part);\n    }\n\n    return true;\n}\n\nPolicyOutput* PolicyManager::resolve_policy_output(const std::string& domain,\n                                                   Policy* policy,\n                                                   QuResult* qu_result,\n                                                   const PolicyOutputSession& session,\n                                                   const RequestContext& context) {\n    // Process parameters\n    std::unordered_map<std::string, std::string> param_map;\n    // Default parameters\n    for (auto const& context: session.context) {\n        if (context.key == \"dmkit_param_last_tts\") {\n            param_map[context.key] =  context.value;\n            continue;\n        }\n        std::string param_key = \"dmkit_param_context_\";\n        param_key += context.key;\n        param_map[param_key] =  context.value;\n    }\n    for (auto const& slot: qu_result->slots()) {\n        std::string param_key = \"dmkit_param_slot_\";\n        param_key += slot.key();\n        if (param_map.find(param_key) != param_map.end()) {\n            continue;\n        }\n        std::string param_value = slot.normalized_value();\n        if (param_value.empty()) {\n            param_value = slot.value();\n        }\n        param_map[param_key] = param_value;\n    }\n    for (auto const& param: policy->params()) {\n        APP_LOG(TRACE) << \"resolving parameter [\" << param.name << \"]\";\n        std::string value;\n        if (param.type == \"slot_val\" || param.type == \"slot_val_ori\") {\n            bool success = false;\n            std::vector<std::string> args;\n            utils::split(param.value, ',', args);\n            int index = 0;\n            if (args.size() >= 2 && !utils::try_atoi(args[1], index)) {\n                APP_LOG(WARNING) << \"Invalid index for slot_val parameter: \" << param.value;\n                index = -1;\n            }\n            for (auto const& slot: qu_result->slots()) {\n                if (index < 0) {\n                    break;\n                }\n                if (slot.key() == args[0]) {\n                    if (index > 0) {\n                        index--;\n                        continue;\n                    }\n                    if (param.type == \"slot_val\" && !slot.normalized_value().empty()) {\n                        value = slot.normalized_value();\n                        success = true;\n                        break;\n                    }\n                    value = slot.value();\n                    success = true;\n                    break;\n                }\n            }\n            if (!success) {\n                if (param.required) {\n                    return nullptr;\n                }\n                value = param.default_value;\n            }\n        } else if (param.type == \"qu_intent\") {\n            value = qu_result->intent();\n        } else if (param.type == \"session_state\") {\n            value = session.state;\n        } else if (param.type == \"session_context\") {\n            bool success = false;\n            for (auto const& obj: session.context) {\n                if (obj.key == param.value) {\n                    value = obj.value;\n                    success = true;\n                    break;\n                }\n            }\n            if (!success) {\n                if (param.required) {\n                    return nullptr;\n                }\n                value = param.default_value;\n            }\n        }else if (param.type == \"const\") {\n            value = param.value;\n        } else if (param.type == \"string\") {\n            value = param.value;\n            if (!try_resolve_params(value, param_map)) {\n                if (param.required) {\n                    return nullptr;\n                }\n                value = param.default_value;\n            }\n        } else if (param.type == \"request_param\") {\n            const std::unordered_map<std::string, std::string> request_params = context.params();\n            std::unordered_map<std::string, std::string>::const_iterator find_res\n                = request_params.find(param.value);\n            bool success = false;\n            if (find_res != request_params.end()) {\n                value = find_res->second;\n                success = true;\n            }\n            if (!success) {\n                if (param.required) {\n                    return nullptr;\n                }\n                value = param.default_value;\n            }\n        } else if (param.type == \"func_val\") {\n            std::string func_val = param.value;\n            std::string func_name;\n            std::vector<std::string> args;\n            std::size_t pos = func_val.find(':');\n            bool has_error = false;\n            if (pos == std::string::npos || pos == func_val.length() - 1) {\n                func_name = func_val;\n                if (!try_resolve_params(func_name, param_map)) {\n                    has_error = true;\n                }\n            } else {\n                func_name = func_val.substr(0, pos);\n                if (!try_resolve_params(func_name, param_map)) {\n                    has_error = true;;\n                }\n                std::string arg_list = func_val.substr(pos + 1);\n                if (!try_resolve_param_list(arg_list, ',', param_map, args)) {\n                    has_error = true;\n                }\n            }\n            utils::trim(func_name);\n            if (has_error || this->_user_function_manager->call_user_function(func_name, args, context, value) != 0) {\n                has_error = true;\n            }\n            if (has_error) {\n                if (param.required) {\n                    return nullptr;\n                }\n                value = param.default_value;\n            }\n        } else {\n            APP_LOG(WARNING) << \"Unknown param type \" << param.type;\n            if (param.required) {\n                return nullptr;\n            }\n            value = param.default_value;\n        }\n        param_map[param.name] =  value;\n        APP_LOG(TRACE) << \"Parameter value [\" << value << \"]\";\n    }\n\n    int selected_output_index = -1;\n    for (unsigned int i = 0; i < policy->outputs().size(); ++i) {\n        bool failed = false;\n        // Process assertions\n        APP_LOG(TRACE) << \"Candidate output size [\" << policy->outputs().size() << \"]\";\n        for (unsigned int j = 0; j < policy->outputs()[i].assertions.size(); ++j) {\n            std::string assertion_type = policy->outputs()[i].assertions[j].type;\n            std::string assertion_value = policy->outputs()[i].assertions[j].value;\n            if (!try_resolve_params(assertion_value, param_map)) {\n                failed = true;\n                break;\n            }\n            APP_LOG(TRACE) << \"evaluating assertion, type[\" << assertion_type << \"] value[\" << assertion_value << \"]\";\n            if (assertion_type == \"not_empty\") {\n                if (assertion_value.empty()) {\n                    failed = true;\n                    break;\n                }\n            } else if (assertion_type == \"empty\") {\n                if (!assertion_value.empty()) {\n                    failed = true;\n                    break;\n                }\n            } else if (assertion_type == \"in\") {\n                std::vector<std::string> value_list;\n                bool has_match = false;\n                if (try_resolve_param_list(assertion_value, ',', param_map, value_list)) {\n                    for (unsigned int k = 1; k < value_list.size(); k++) {\n                        if (value_list[0] == value_list[k]) {\n                            has_match = true;\n                            break;\n                        }\n                    }\n                }\n                if (!has_match) {\n                    failed = true;\n                }\n            } else if (assertion_type == \"not_in\") {\n                std::vector<std::string> value_list;\n                if (try_resolve_param_list(assertion_value, ',', param_map, value_list)) {\n                    for (unsigned int k = 1; k < value_list.size(); k++) {\n                        if (value_list[0] == value_list[k]) {\n                            failed = true;\n                            break;\n                        }\n                    }\n                }\n            } else if (assertion_type == \"eq\") {\n                std::vector<std::string> value_list;\n                if (!try_resolve_param_list(assertion_value, ',', param_map, value_list)\n                    || value_list.size() < 2\n                    || value_list[0] != value_list[1]) {\n                    failed = true;\n                }\n            } else if (assertion_type == \"gt\") {\n                std::vector<std::string> value_list;\n                double left_val = 0;\n                double right_val = 0;\n                if (!try_resolve_param_list(assertion_value, ',', param_map, value_list)\n                    || value_list.size() < 2\n                    || !utils::try_atof(value_list[0], left_val)\n                    || !utils::try_atof(value_list[1], right_val)\n                    || left_val <= right_val) {\n                    failed  = true;\n                }\n            } else if (assertion_type == \"ge\") {\n                std::vector<std::string> value_list;\n                double left_val = 0;\n                double right_val = 0;\n                if (!try_resolve_param_list(assertion_value, ',', param_map, value_list)\n                    || value_list.size() < 2\n                    || !utils::try_atof(value_list[0], left_val)\n                    || !utils::try_atof(value_list[1], right_val)\n                    || left_val < right_val) {\n                    failed  = true;\n                }\n            } else {\n                APP_LOG(WARNING) << \"Unknown assertion type \" << assertion_type;\n                failed = true;\n                break;\n            }\n        }\n        if (!failed) {\n            LOG(TRACE) << \"selected output at index [\" << i << \"]\";\n            selected_output_index = i;\n            break;\n        }\n    }\n    if (selected_output_index == -1) {\n        return nullptr;\n    }\n\n    PolicyOutput output;\n    output.meta = policy->outputs()[selected_output_index].meta;\n    output.session = policy->outputs()[selected_output_index].session;\n    output.qu = policy->outputs()[selected_output_index].qu;\n    output.results = policy->outputs()[selected_output_index].results;\n\n    for (unsigned int i = 0; i < output.meta.size(); ++i) {\n        if (!try_resolve_params(output.meta[i].key, param_map)) {\n            return nullptr;\n        }\n        if (!try_resolve_params(output.meta[i].value, param_map)) {\n            return nullptr;\n        }\n    }\n    if (!try_resolve_params(output.session.domain, param_map)) {\n        return nullptr;\n    }\n    if (!try_resolve_params(output.session.state, param_map)) {\n        return nullptr;\n    }\n    for (unsigned int i = 0; i < output.session.context.size(); ++i) {\n        if (!try_resolve_params(output.session.context[i].key, param_map)) {\n            return nullptr;\n        }\n        if (!try_resolve_params(output.session.context[i].value, param_map)) {\n            return nullptr;\n        }\n    }\n    if (!try_resolve_params(output.qu.domain, param_map)) {\n        return nullptr;\n    }\n    if (!try_resolve_params(output.qu.intent, param_map)) {\n        return nullptr;\n    }\n    for (unsigned int i = 0; i < output.qu.slots.size(); ++i) {\n        if (!try_resolve_params(output.qu.slots[i].key, param_map)) {\n            return nullptr;\n        }\n        if (!try_resolve_params(output.qu.slots[i].value, param_map)) {\n            return nullptr;\n        }\n        if (!try_resolve_params(output.qu.slots[i].normalized_value, param_map)) {\n            return nullptr;\n        }\n    }\n    for (unsigned int i = 0; i < output.results.size(); ++i) {\n        if (output.results[i].values.empty()) {\n            APP_LOG(WARNING) << \"empty result value!\";\n            return nullptr;\n        }\n        if (output.results[i].values.size() > 1) {\n            int size = output.results[i].values.size();\n            int index = std::time(nullptr) % size;\n            if (index < 0 || index >= size) {\n                index = 0;\n            }\n            std::string value = output.results[i].values[index];\n            output.results[i].values.clear();\n            output.results[i].values.push_back(value);\n        }\n        if (!try_resolve_params(output.results[i].values[0], param_map)) {\n            return nullptr;\n        }\n    }\n\n    PolicyOutput* output_ptr = new PolicyOutput();\n    *output_ptr = output;\n    output_ptr->session.domain = domain;\n\n    // Saved parameters\n    for (auto const& param: param_map) {\n        if (param.first.find(\"dmkit_param_context_\") != 0) {\n            continue;\n        }\n        std::string context_key = param.first.substr(20);\n        if (context_key.empty()) {\n            continue;\n        }\n        KVPair context = {context_key, param.second};\n        output_ptr->session.context.push_back(context);\n    }\n    std::string first_tts;\n    for (unsigned int i = 0; i < output_ptr->results.size(); ++i) {\n        if (output_ptr->results[i].type == \"tts\") {\n            first_tts = output_ptr->results[i].values[0];\n            break;\n        }\n    }\n    KVPair last_tts_context = {\"dmkit_param_last_tts\", first_tts};\n    output_ptr->session.context.push_back(last_tts_context);\n\n    return output_ptr;\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/policy_manager.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_POLICY_MANAGER_H\n#define DMKIT_POLICY_MANAGER_H\n\n#include <memory>\n#include <mutex>\n#include <string>\n#include <thread>\n#include <vector>\n#include \"butil.h\"\n#include \"policy.h\"\n#include \"qu_result.h\"\n#include \"request_context.h\"\n#include \"user_function_manager.h\"\n\nnamespace dmkit {\n\ntypedef std::vector<Policy*> PolicyVector;\ntypedef BUTIL_NAMESPACE::FlatMap<std::string, PolicyVector*> IntentPolicyMap;\n\n// Holds all policies given a domain.\nclass DomainPolicy {\npublic:\n    DomainPolicy(const std::string& name, int score, IntentPolicyMap* intent_policy_map);\n    ~DomainPolicy();\n    const std::string& name();\n    int score();\n    // Maps a intent to a vector of policies\n    IntentPolicyMap* intent_policy_map();\n\nprivate:\n    std::string _name;\n    int _score;\n    IntentPolicyMap* _intent_policy_map;\n};\n\ntypedef BUTIL_NAMESPACE::FlatMap<std::string, DomainPolicy*> DomainPolicyMap;\ntypedef BUTIL_NAMESPACE::FlatMap<std::string, DomainPolicyMap*> ProductPolicyMap;\n\nclass PolicyManager {\npublic:\n    PolicyManager();\n    ~PolicyManager();\n    int init(const char* dir_path, const char* conf_file);\n    int reload();\n    // Resolve a policy output given a qu result and current dm session\n    PolicyOutput* resolve(const std::string& product,\n                          BUTIL_NAMESPACE::FlatMap<std::string, QuResult*>* qu_result,\n                          const PolicyOutputSession& session,\n                          const RequestContext& context);\n\n    static int policy_conf_change_callback(void* param);\n\nprivate:\n    DomainPolicyMap* load_domain_policy_map(const std::string& product_name,\n                                             const rapidjson::Value& product_json);\n\n    DomainPolicy* load_domain_policy(const std::string& domain_name,\n                                     int score,\n                                     const std::string& conf_path);\n\n    Policy* find_best_policy(DomainPolicy* domain_policy,\n                             QuResult* qu_result,\n                             const PolicyOutputSession& session,\n                             const RequestContext& context);\n\n    PolicyOutput* resolve_policy_output(const std::string& domain,\n                                        Policy* policy,\n                                        QuResult* qu_result,\n                                        const PolicyOutputSession& session,\n                                        const RequestContext& context);\n\n    ProductPolicyMap* load_policy_dict();\n\n    std::string _conf_file_path;\n    std::shared_ptr<ProductPolicyMap> _p_policy_dict;\n\n    UserFunctionManager* _user_function_manager;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_POLICY_MANAGER_H\n"
  },
  {
    "path": "src/qu_result.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"qu_result.h\"\n#include \"app_log.h\"\n#include \"utils.h\"\n\nnamespace dmkit {\n\nSlot::Slot(const std::string& key, const std::string& value, const std::string& normalized_value)\n    : _key(key), _value(value), _normalized_value(normalized_value) {\n}\n\nconst std::string& Slot::key() const {\n    return this->_key;\n}\n\nconst std::string& Slot::value() const {\n    return this->_value;\n}\n\nconst std::string& Slot::normalized_value() const {\n    return this->_normalized_value;\n}\n\nQuResult::QuResult(const std::string& domain,\n                   const std::string& intent,\n                   const std::vector<Slot>& slots)\n    : _domain(domain), _intent(intent), _slots(slots) {\n}\n\n// Parse QU result from dialog state in unit response\nQuResult* QuResult::parse_from_dialog_state(const std::string& domain, \n                                            const rapidjson::Value& value) {\n    if (!value.IsObject()) {\n        APP_LOG(WARNING) << \"Failed to parse qu result from json, not an object\";\n        return nullptr;\n    }\n    \n    if (!value.HasMember(\"intents\") || !value[\"intents\"].IsArray() || value[\"intents\"].Size() < 1) {\n        APP_LOG(WARNING) << \"Failed to parse qu result from json\";\n    }\n    int intents_size = value[\"intents\"].Size();\n    std::string intent = value[\"intents\"][intents_size - 1][\"name\"].GetString();\n    std::vector<Slot> slots;\n    for (auto& m_slot: value[\"user_slots\"].GetObject()) {\n        std::string tag = m_slot.name.GetString();\n        for (auto& m_value: m_slot.value.GetObject()[\"values\"].GetObject()) {\n            int slot_state = m_value.value.GetObject()[\"state\"].GetInt();\n            // Slot state possible values are\n            // 0: slot not filled\n            // 1: slot is filled by default value\n            // 2: slot is filled by SLU\n            // 4: slot was filled but has been replaced by other value\n            if (slot_state == 0 || slot_state == 4) {\n                continue;\n            }\n            std::string normalized_value = m_value.name.GetString();\n            std::string value = m_value.value.GetObject()[\"original_name\"].GetString();\n            Slot slot(tag, value, normalized_value);\n            slots.push_back(slot);\n        }\n    }\n\n    QuResult* result = new QuResult(domain, intent, slots);\n    APP_LOG(TRACE) << result->to_string();\n    return result;\n}\n\nconst std::string& QuResult::domain() const {\n    return this->_domain;\n}\n\nconst std::string& QuResult::intent() const {\n    return this->_intent;\n}\n\nconst std::vector<Slot>& QuResult::slots() const {\n    return this->_slots;\n}\n\nstd::string QuResult::to_string() const {\n    std::string result;\n    result += \"domain:\";\n    result += this->domain();\n    result += \" intent:\";\n    result += this->intent();\n    result += \" slots: {\";\n    for (auto iter = this->slots().begin(); iter != this->slots().end(); ++iter) {\n        result += iter->key();\n        result += \":\";\n        result += iter->value();\n        if (!iter->normalized_value().empty()) {\n            result += \"(\";\n            result += iter->normalized_value();\n            result += \")\";\n        }\n        result += \" \";\n    }\n    result += \"}\";\n\n    return result;\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/qu_result.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_QU_RESULT_H\n#define DMKIT_QU_RESULT_H\n\n#include <string>\n#include <vector>\n#include \"rapidjson.h\"\n\nnamespace dmkit {\n\nclass Slot {\npublic:\n    Slot(const std::string& key, const std::string& value, const std::string& normalized_value);\n    \n    const std::string& key() const;\n    const std::string& value() const;\n    const std::string& normalized_value() const;\n\nprivate:\n    std::string _key;\n    std::string _value;\n    std::string _normalized_value;\n};\n\n// Query Understanding, or natural language understanding (NLU) results for user input,\n// generally includes domain, intent and slots.\nclass QuResult {\npublic:\n    QuResult(const std::string& domain, const std::string& intent, const std::vector<Slot>& slots);\n\n    static QuResult* parse_from_dialog_state(const std::string& domain,\n                                             const rapidjson::Value& value);\n\n    const std::string& domain() const;\n    const std::string& intent() const;\n    const std::vector<Slot>& slots() const;\n\n    std::string to_string() const;\nprivate:\n    std::string _domain;\n    std::string _intent;\n    std::vector<Slot> _slots;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_QU_RESULT_H\n"
  },
  {
    "path": "src/rapidjson.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef  DMKIT_RAPIDJSON_H\n#define  DMKIT_RAPIDJSON_H\n\n#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n\n#pragma GCC diagnostic push\n\n#pragma GCC diagnostic ignored \"-Wunused-local-typedefs\"\n\n#endif\n\n#include \"thirdparty/rapidjson/allocators.h\"\n#include \"thirdparty/rapidjson/document.h\"\n#include \"thirdparty/rapidjson/encodedstream.h\"\n#include \"thirdparty/rapidjson/encodings.h\"\n#include \"thirdparty/rapidjson/filereadstream.h\"\n#include \"thirdparty/rapidjson/filewritestream.h\"\n#include \"thirdparty/rapidjson/fwd.h\"\n#include \"thirdparty/rapidjson/istreamwrapper.h\"\n#include \"thirdparty/rapidjson/memorybuffer.h\"\n#include \"thirdparty/rapidjson/memorystream.h\"\n#include \"thirdparty/rapidjson/ostreamwrapper.h\"\n#include \"thirdparty/rapidjson/pointer.h\"\n#include \"thirdparty/rapidjson/prettywriter.h\"\n#include \"thirdparty/rapidjson/rapidjson.h\"\n#include \"thirdparty/rapidjson/reader.h\"\n#include \"thirdparty/rapidjson/schema.h\"\n#include \"thirdparty/rapidjson/stream.h\"\n#include \"thirdparty/rapidjson/stringbuffer.h\"\n#include \"thirdparty/rapidjson/writer.h\"\n\n#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)\n#pragma GCC diagnostic pop\n#endif\n\n#endif  //DMKIT_RAPIDJSON_H\n"
  },
  {
    "path": "src/remote_service_manager.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"remote_service_manager.h\"\n#include <curl/curl.h>\n#include <cstdio>\n#include <string>\n#include \"app_log.h\"\n#include \"file_watcher.h\"\n#include \"rapidjson.h\"\n#include \"thread_data_base.h\"\n\nnamespace dmkit {\n\nRemoteServiceManager::RemoteServiceManager() {\n}\n\nRemoteServiceManager::~RemoteServiceManager() {\n    FileWatcher::get_instance().unregister_file(this->_conf_file_path);\n    this->_p_channel_map.reset();\n}\n\nstatic inline void destroy_channel_map(ChannelMap* p) {\n    APP_LOG(TRACE) << \"Destroying service map...\";\n    if (nullptr == p) {\n        return;\n    }\n    for (auto& channel : *p) {\n        if (nullptr != channel.second.channel) {\n            delete channel.second.channel;\n            channel.second.channel = nullptr;\n            APP_LOG(TRACE) << \"Destroyed service\" << channel.first;\n        }\n    }\n    delete p;\n}\n\nint RemoteServiceManager::init(const char* path, const char* conf) {\n    std::string file_path;\n    if (path != nullptr) {\n        file_path += path;\n    }\n    if (!file_path.empty() && file_path[file_path.length() - 1] != '/') {\n        file_path += '/';\n    }\n    if (conf != nullptr) {\n        file_path += conf;\n    }\n    this->_conf_file_path = file_path;\n\n    ChannelMap* channel_map = this->load_channel_map();\n    if (channel_map == nullptr) {\n        APP_LOG(ERROR) << \"Failed to init RemoteServiceManager, cannot load channel map\";\n        return -1;\n    }\n\n    this->_p_channel_map.reset(channel_map,\n                               [](ChannelMap* p) { destroy_channel_map(p); });\n\n    FileWatcher::get_instance().register_file(\n        this->_conf_file_path, RemoteServiceManager::service_conf_change_callback, this, true);\n\n    return 0;\n}\n\nint RemoteServiceManager::reload() {\n    APP_LOG(TRACE) << \"Reloading RemoteServiceManager...\";\n    ChannelMap* channel_map = this->load_channel_map();\n    if (channel_map == nullptr) {\n        APP_LOG(ERROR) << \"Failed to reload RemoteServiceManager, cannot load channel map\";\n        return -1;\n    }\n\n    this->_p_channel_map.reset(channel_map,\n                               [](ChannelMap* p) { destroy_channel_map(p); });\n    APP_LOG(TRACE) << \"Reload finished.\";\n    return 0;\n}\n\nint RemoteServiceManager::service_conf_change_callback(void* param) {\n    RemoteServiceManager* rsm = (RemoteServiceManager*)param;\n    return rsm->reload();\n}\n\nint RemoteServiceManager::call(const std::string& service_name,\n                               const RemoteServiceParam& params,\n                               RemoteServiceResult& result) const {\n    std::shared_ptr<ChannelMap> p_channel_map(this->_p_channel_map);\n    if (p_channel_map == nullptr) {\n        APP_LOG(ERROR) << \"Remote service call failed, channel map is null\";\n        return -1;\n    }\n\n    if (p_channel_map->find(service_name) == p_channel_map->end()) {\n        APP_LOG(ERROR) << \"Remote service call failed, cannot find service \" << service_name;\n        return -1;\n    }\n\n    RemoteServiceChannel& service_channel = (*p_channel_map)[service_name];\n\n    APP_LOG(TRACE) << \"Calling service \" << service_name;\n\n    int ret = 0;\n    std::string remote_side;\n    int latency = 0;\n    if (service_channel.protocol == \"http\") {\n        if (service_channel.channel != nullptr) {\n            ret = this->call_http_by_BRPC_NAMESPACE(service_channel.channel,\n                                          params.url,\n                                          params.http_method,\n                                          service_channel.headers,\n                                          params.payload,\n                                          result.result,\n                                          remote_side,\n                                          latency);\n        } else {\n            ret = this->call_http_by_curl(params.url,\n                                          params.http_method,\n                                          service_channel.headers,\n                                          params.payload,\n                                          service_channel.timeout_ms,\n                                          service_channel.max_retry,\n                                          result.result,\n                                          remote_side,\n                                          latency);\n        }\n    } else {\n        APP_LOG(ERROR) << \"Remote service call failed. Unknown protocol\" << service_channel.protocol;\n        ret = -1;\n    }\n    std::string log_str;\n    log_str += \"remote:\";\n    log_str += remote_side;\n    log_str += \"|tm:\";\n    log_str += std::to_string(latency);\n    log_str += \"|ret:\";\n    log_str += std::to_string(ret);\n    std::string log_key = \"service_\";\n    log_key += service_name;\n\n    APP_LOG(TRACE) << \"remote_side=\" << remote_side << \", cost=\" << latency;\n    ThreadDataBase* tls = static_cast<ThreadDataBase*>(BRPC_NAMESPACE::thread_local_data());\n    // All backend requests are logged.\n    tls->add_notice_log(log_key, log_str);\n\n    return ret;\n}\n\nChannelMap* RemoteServiceManager::load_channel_map() {\n    APP_LOG(TRACE) << \"Loading channel map...\";\n    FILE* fp = fopen(this->_conf_file_path.c_str(), \"r\");\n    if (fp == nullptr) {\n        APP_LOG(ERROR) << \"Failed to open file \" << this->_conf_file_path;\n        return nullptr;\n    }\n    char read_buffer[1024];\n    rapidjson::FileReadStream is(fp, read_buffer, sizeof(read_buffer));\n    rapidjson::Document doc;\n    doc.ParseStream(is);\n    fclose(fp);\n\n    if (doc.HasParseError() || !doc.IsObject()) {\n        APP_LOG(ERROR) << \"Failed to parse RemoteServiceManager settings\";\n        return nullptr;\n    }\n\n    ChannelMap* channel_map = new ChannelMap();\n    rapidjson::Value::ConstMemberIterator service_iter;\n    for (service_iter = doc.MemberBegin(); service_iter != doc.MemberEnd(); ++service_iter) {\n        // Service name as the key for the channel.\n        std::string service_name = service_iter->name.GetString();\n        if (!service_iter->value.IsObject()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type object for service setting.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        const rapidjson::Value& settings = service_iter->value;\n        rapidjson::Value::ConstMemberIterator setting_iter;\n        // Naming service url such as https://www.baidu.com.\n        // All supported url format can be found in BRPC docs.\n        setting_iter = settings.FindMember(\"naming_service_url\");\n        if (setting_iter == settings.MemberEnd() || !setting_iter->value.IsString()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type String for property naming_service_url.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        std::string naming_service_url = setting_iter->value.GetString();\n        // Load balancer name such as random, rr.\n        // All supported balancer can be found in BRPC docs.\n        setting_iter = settings.FindMember(\"load_balancer_name\");\n        if (setting_iter == settings.MemberEnd() || !setting_iter->value.IsString()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type String for property load_balancer_name.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        std::string load_balancer_name = setting_iter->value.GetString();\n        // Protocol for the channel.\n        // Currently we support http.\n        setting_iter = settings.FindMember(\"protocol\");\n        if (setting_iter == settings.MemberEnd() || !setting_iter->value.IsString()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type String for property protocol.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        std::string protocol = setting_iter->value.GetString();\n        // Client to use for sending request.\n        setting_iter = settings.FindMember(\"client\");\n        std::string client;\n        if (setting_iter != settings.MemberEnd() && setting_iter->value.IsString()) {\n            client = setting_iter->value.GetString();\n        }\n        // Timeout value in millisecond.\n        setting_iter = settings.FindMember(\"timeout_ms\");\n        if (setting_iter == settings.MemberEnd() || !setting_iter->value.IsInt()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type Int for property timeout_ms.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        int timeout_ms = setting_iter->value.GetInt();\n        // Retry count.\n        setting_iter = settings.FindMember(\"retry\");\n        if (setting_iter == settings.MemberEnd() || !setting_iter->value.IsInt()) {\n            APP_LOG(ERROR) << \"Invalid service settings for \" << service_name\n                << \", expecting type Int for property retry.\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n        int retry = setting_iter->value.GetInt();\n        // Headers for a http request.\n        std::vector<std::pair<std::string, std::string>> headers;\n        setting_iter = settings.FindMember(\"headers\");\n        if (setting_iter != settings.MemberEnd() && setting_iter->value.IsObject()) {\n            const rapidjson::Value& obj_headers = setting_iter->value;\n            rapidjson::Value::ConstMemberIterator header_iter;\n            for (header_iter = obj_headers.MemberBegin();\n                    header_iter != obj_headers.MemberEnd(); ++header_iter) {\n                std::string header_key = header_iter->name.GetString();\n                if (!header_iter->value.IsString()) {\n                    APP_LOG(ERROR) << \"Invalid header value for \" << header_key\n                        << \", expecting type String for header value.\";\n                    destroy_channel_map(channel_map);\n                    return nullptr;\n                }\n                std::string header_value = header_iter->value.GetString();\n                headers.push_back(std::make_pair(header_key, header_value));\n            }\n        }\n\n        BRPC_NAMESPACE::Channel* rpc_channel = nullptr;\n        if (protocol == \"http\") {\n            if (client.empty() || client == \"brpc\") {\n                rpc_channel = new BRPC_NAMESPACE::Channel();\n                BRPC_NAMESPACE::ChannelOptions options;\n                options.protocol = BRPC_NAMESPACE::PROTOCOL_HTTP;\n                options.timeout_ms = timeout_ms;\n                options.max_retry = retry;\n                int ret = rpc_channel->Init(naming_service_url.c_str(), load_balancer_name.c_str(), &options);\n                if (ret != 0) {\n                    APP_LOG(ERROR) << \"Failed to init channel.\";\n                    delete rpc_channel;\n                    destroy_channel_map(channel_map);\n                    return nullptr;\n                }\n            } else if (client == \"curl\") {\n                // curl does not need to init rpc channel\n            } else {\n                APP_LOG(ERROR) << \"Unsupported client value [\" << client << \"].\";\n                destroy_channel_map(channel_map);\n                return nullptr;\n            }\n        } else {\n            APP_LOG(ERROR) << \"Unsupported protocol [\" << protocol\n                << \"] for service [\" << service_name << \"], skipped...\";\n            destroy_channel_map(channel_map);\n            return nullptr;\n        }\n\n        RemoteServiceChannel service_channel {\n            .name = service_name,\n            .protocol = protocol,\n            .channel = rpc_channel,\n            .timeout_ms = timeout_ms,\n            .max_retry = retry,\n            .headers = headers\n        };\n        channel_map->insert({service_name, service_channel});\n        APP_LOG(TRACE) << \"Loaded service \" << service_name;\n    }\n\n    return channel_map;\n}\n\nint RemoteServiceManager::call_http_by_BRPC_NAMESPACE(BRPC_NAMESPACE::Channel* channel,\n                                            const std::string& url,\n                                            const HttpMethod method,\n                                            const std::vector<std::pair<std::string, std::string>>& headers,\n                                            const std::string& payload,\n                                            std::string& result,\n                                            std::string& remote_side,\n                                            int& latency) const {\n    BRPC_NAMESPACE::Controller cntl;\n    cntl.http_request().uri() = url.c_str();\n    if (method == HTTP_METHOD_POST) {\n        cntl.http_request().set_method(BRPC_NAMESPACE::HTTP_METHOD_POST);\n        cntl.request_attachment().append(payload);\n    }\n    for (auto const& header: headers) {\n        if (header.first == \"Content-Type\" || header.first == \"content-type\") {\n            cntl.http_request().set_content_type(header.second);\n            continue;\n        }\n        cntl.http_request().SetHeader(header.first, header.second);\n    }\n\n    channel->CallMethod(NULL, &cntl, NULL, NULL, NULL);\n    if (cntl.Failed()) {\n        APP_LOG(WARNING) << \"Call failed, error: \" << cntl.ErrorText();\n        remote_side = BUTIL_NAMESPACE::endpoint2str(cntl.remote_side()).c_str();\n        latency = cntl.latency_us() / 1000;\n        return -1;\n    }\n    result = cntl.response_attachment().to_string();\n\n    remote_side = BUTIL_NAMESPACE::endpoint2str(cntl.remote_side()).c_str();\n    latency = cntl.latency_us() / 1000;\n\n    return 0;\n}\n\nstatic size_t curl_write_callback(void *contents, size_t size, size_t nmemb, void *userp) {\n    BUTIL_NAMESPACE::IOBuf* buffer = static_cast<BUTIL_NAMESPACE::IOBuf*>(userp);\n    size_t realsize = size * nmemb;\n    buffer->append(contents, realsize);\n    return realsize;\n}\n\nint RemoteServiceManager::call_http_by_curl(const std::string& url,\n                                            const HttpMethod method,\n                                            const std::vector<std::pair<std::string, std::string>>& headers,\n                                            const std::string& payload,\n                                            const int timeout_ms,\n                                            const int max_retry,\n                                            std::string& result,\n                                            std::string& remote_side,\n                                            int& latency) const {\n    // curl does not support retry now\n    (void)max_retry;\n    CURL *curl;\n    CURLcode res;\n    struct curl_slist *curl_headers = nullptr;\n    curl = curl_easy_init();\n    if (!curl) {\n        APP_LOG(ERROR) << \"Failed to init curl\";\n        return -1;\n    }\n    curl_easy_setopt(curl, CURLOPT_URL, url.c_str());\n    BUTIL_NAMESPACE::IOBuf response_buffer;\n    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_write_callback);\n    curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(&response_buffer));\n\n    if (method == HTTP_METHOD_POST) {\n         curl_easy_setopt(curl, CURLOPT_POST, 1L);\n         curl_easy_setopt(curl, CURLOPT_POSTFIELDS, payload.c_str());\n         curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, payload.length());\n    }\n\n    for (auto const& header: headers) {\n        std::string header_value = header.first;\n        header_value += \": \";\n        header_value += header.second;\n        curl_headers = curl_slist_append(curl_headers, header_value.c_str());\n    }\n    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_headers);\n    curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, timeout_ms);\n\n    //curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);\n    res = curl_easy_perform(curl);\n    curl_slist_free_all(curl_headers);\n    if(res != CURLE_OK) {\n        APP_LOG(ERROR) << \"curl failed, error: \" << curl_easy_strerror(res);\n        curl_easy_cleanup(curl);\n        return -1;\n    }\n\n    double total_time;\n    res = curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);\n    if (CURLE_OK == res) {\n        latency = total_time * 1000;\n    }\n    char *ip = nullptr;\n    res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ip);\n    if (CURLE_OK == res && ip != nullptr) {\n        remote_side = ip;\n    }\n\n    curl_easy_cleanup(curl);\n    result = response_buffer.to_string();\n\n    return 0;\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/remote_service_manager.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_REMOTE_SERVICE_MANAGER_H\n#define DMKIT_REMOTE_SERVICE_MANAGER_H\n\n#include <memory>\n#include <string>\n#include <unordered_map>\n#include <utility>\n#include <vector>\n#include \"brpc.h\"\n#include \"butil.h\"\n\nnamespace dmkit {\n\nenum HttpMethod {\n    // Set to the same number as the method defined in baidu::rpc::HttpMethod\n    HTTP_METHOD_DELETE      =   0,\n    HTTP_METHOD_GET         =   1,\n    HTTP_METHOD_POST        =   3,\n    HTTP_METHOD_PUT         =   4\n};\n\nstruct RemoteServiceParam {\n    // Url for http service\n    std::string url;\n    // Http method\n    HttpMethod http_method;\n    // Request body\n    std::string payload;\n};\n\nstruct RemoteServiceResult {\n    // Response body\n    std::string result;\n};\n\nstruct RemoteServiceChannel {\n    // Name of the channel for rpc call\n    std::string name;\n    // Protocol such as http\n    std::string protocol;\n    // Rpc channel instance\n    BRPC_NAMESPACE::Channel *channel;\n    // timeout in milliseconds\n    int timeout_ms;\n    // retry count\n    int max_retry;\n    // Headers for http procotol\n    std::vector<std::pair<std::string, std::string>> headers;\n};\n\n// Type for channel map\ntypedef std::unordered_map<std::string, RemoteServiceChannel> ChannelMap;\n\n// A configurable remote service manager class.\n// All remote service channels are created with configuration file\n// when initialization. Caller calls a remote service by supplying\n// the service name and other parameters.\nclass RemoteServiceManager {\npublic:\n    RemoteServiceManager();\n\n    ~RemoteServiceManager();\n\n    // Initalization with a json configuration file.\n    int init(const char *path, const char *conf);\n\n    // Reload config.\n    int reload();\n\n    // Callback when service conf changed.\n    static int service_conf_change_callback(void* param);\n\n    // Call a remote service with specifid service name.\n    int call(const std::string& servie_name,\n             const RemoteServiceParam& params,\n             RemoteServiceResult &result) const;\n\nprivate:\n    // Http is the most common protocol.\n   int call_http_by_BRPC_NAMESPACE(BRPC_NAMESPACE::Channel* channel,\n                         const std::string& url,\n                         const HttpMethod method,\n                         const std::vector<std::pair<std::string, std::string>>& headers,\n                         const std::string& payload,\n                         std::string& result,\n                         std::string& remote_side,\n                         int& latency) const;\n\n    int call_http_by_curl(const std::string& url,\n                          const HttpMethod method,\n                          const std::vector<std::pair<std::string, std::string>>& headers,\n                          const std::string& payload,\n                          const int timeout_ms,\n                          const int max_retry,\n                          std::string& result,\n                          std::string& remote_side,\n                          int& latency) const;\n\n    ChannelMap* load_channel_map();\n\n    std::string _conf_file_path;\n    std::shared_ptr<ChannelMap> _p_channel_map;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_THREAD_DATA_BASE_H\n"
  },
  {
    "path": "src/request_context.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"request_context.h\"\n\nnamespace dmkit {\n\nRequestContext::RequestContext(RemoteServiceManager* remote_service_manager,\n                               const std::string& qid,\n                               const std::unordered_map<std::string, std::string>& params)\n    : _remote_service_manager(remote_service_manager), _qid(qid), _params(params) {\n\n}\n\nRequestContext::~RequestContext() {\n}\n\nconst RemoteServiceManager* RequestContext::remote_service_manager() const {\n    return _remote_service_manager;\n}\n\nconst std::string& RequestContext::qid() const {\n    return _qid;\n}\n\nconst std::unordered_map<std::string, std::string>& RequestContext::params() const {\n    return _params;\n}\n\nbool RequestContext::set_param_value(const std::string& param_name, const std::string& value) {\n    this->_params[param_name] = value;\n    return true;\n}\n\nbool RequestContext::try_get_param(const std::string& param_name, std::string& value) const {\n    value.clear();\n    auto search = this->_params.find(param_name);\n    if (search == this->_params.end()) {\n        return false;\n    }\n\n    value = search->second;\n    return true;\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/request_context.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_REQUEST_CONTEXT_H\n#define DMKIT_REQUEST_CONTEXT_H\n\n#include <string>\n#include <unordered_map>\n#include \"remote_service_manager.h\"\n\nnamespace dmkit {\n\n// Request context for user functions to access,\n// including request parameters and an remote_service_manager instance\nclass RequestContext {\npublic:\n    RequestContext(RemoteServiceManager* remote_service_manager,\n                   const std::string& qid,\n                   const std::unordered_map<std::string, std::string>& params);\n    ~RequestContext();\n\n    const RemoteServiceManager* remote_service_manager() const;\n    const std::string& qid() const;\n    const std::unordered_map<std::string, std::string>& params() const;\n    bool set_param_value(const std::string& param_name, const std::string& value);\n    bool try_get_param(const std::string& param_name, std::string& value) const;\n\nprivate:\n    RemoteServiceManager* _remote_service_manager;\n    std::string _qid;\n    std::unordered_map<std::string, std::string> _params;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_THREAD_DATA_BASE_H\n"
  },
  {
    "path": "src/server.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include <gflags/gflags.h>\n#include \"app_container.h\"\n#include \"app_log.h\"\n#include \"brpc.h\"\n#include \"http.pb.h\"\n\nDEFINE_int32(port, -1, \"TCP Port of this server\");\nDEFINE_int32(internal_port, -1, \"Only allow builtin services at this port\");\nDEFINE_int32(idle_timeout_s, -1, \"Connection will be closed if there is no read/write operations during this time\");\nDEFINE_int32(max_concurrency, 0, \"Limit of requests processing in parallel\");\nDEFINE_string(url_path, \"\", \"Url path of the app\");\nDEFINE_bool(log_to_file, false, \"Log to file\");\n\nnamespace dmkit {\n\n// Service with static path.\nclass HttpServiceImpl : public HttpService {\npublic:\n    HttpServiceImpl() {};\n\n    virtual ~HttpServiceImpl() noexcept {};\n\n    int init() {\n        return this->_app_container.load_application();\n    }\n\n    ThreadLocalDataFactory* get_thread_local_data_factory() {\n        return this->_app_container.get_thread_local_data_factory();\n    }\n\n    void run(google::protobuf::RpcController* cntl_base,\n              const HttpRequest*,\n              HttpResponse*,\n              google::protobuf::Closure* done) {\n        // This object helps you to call done->Run() in RAII style. If you need\n        // to process the request asynchronously, pass done_guard.release().\n        BRPC_NAMESPACE::ClosureGuard done_guard(done);\n\n        BRPC_NAMESPACE::Controller* cntl = static_cast<BRPC_NAMESPACE::Controller*>(cntl_base);\n        this->_app_container.run(cntl);\n    }\n\nprivate:\n    AppContainer _app_container;\n};\n\n} // namespace dmkit\n\nint main(int argc, char* argv[]) {\n    // Parse gflags. We recommend you to use gflags as well.\n    GFLAGS_NS::SetCommandLineOption(\"flagfile\", \"conf/gflags.conf\");\n    GFLAGS_NS::ParseCommandLineFlags(&argc, &argv, true);\n\n#ifdef BUTIL_ENABLE_COMLOG_SINK\n    if (FLAGS_log_to_file) {\n        if (logging::ComlogSink::GetInstance()->SetupFromConfig(\"conf/log.conf\") != 0) {\n            APP_LOG(ERROR) << \"Fail to setup comlog from conf/log.conf\";\n            return -1;\n        }\n    }\n#endif\n\n    // Generally you only need one Server.\n    BRPC_NAMESPACE::Server server;\n    dmkit::HttpServiceImpl http_svc;\n\n    if (http_svc.init() != 0) {\n        APP_LOG(ERROR) << \"Fail to init http_svc\";\n        return -1;\n    }\n\n    // Add services into server. Notice the second parameter, because the\n    // service is put on stack, we don't want server to delete it, otherwise\n    // use baidu::rpc::SERVER_OWNS_SERVICE.\n    std::string mapping = FLAGS_url_path + \" => run\";\n    if (server.AddService(&http_svc,\n                          BRPC_NAMESPACE::SERVER_DOESNT_OWN_SERVICE,\n                          mapping.c_str()) != 0) {\n        APP_LOG(ERROR) << \"Fail to add http_svc\";\n        return -1;\n    }\n\n    // Start the server.\n    BRPC_NAMESPACE::ServerOptions options;\n    options.idle_timeout_sec = FLAGS_idle_timeout_s;\n    options.max_concurrency = FLAGS_max_concurrency;\n    options.internal_port = FLAGS_internal_port;\n    options.thread_local_data_factory = http_svc.get_thread_local_data_factory();\n\n    APP_LOG(TRACE) << \"Starting server...\";\n    if (server.Start(FLAGS_port, &options) != 0) {\n        APP_LOG(ERROR) << \"Fail to start server\";\n        return -1;\n    }\n\n    // Wait until Ctrl-C is pressed, then Stop() and Join() the server.\n    server.RunUntilAskedToQuit();\n    return 0;\n}\n"
  },
  {
    "path": "src/thirdparty/rapidjson/allocators.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ALLOCATORS_H_\n#define RAPIDJSON_ALLOCATORS_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Allocator\n\n/*! \\class rapidjson::Allocator\n    \\brief Concept for allocating, resizing and freeing memory block.\n    \n    Note that Malloc() and Realloc() are non-static but Free() is static.\n    \n    So if an allocator need to support Free(), it needs to put its pointer in \n    the header of memory block.\n\n\\code\nconcept Allocator {\n    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().\n\n    // Allocate a memory block.\n    // \\param size of the memory block in bytes.\n    // \\returns pointer to the memory block.\n    void* Malloc(size_t size);\n\n    // Resize a memory block.\n    // \\param originalPtr The pointer to current memory block. Null pointer is permitted.\n    // \\param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)\n    // \\param newSize the new size in bytes.\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);\n\n    // Free a memory block.\n    // \\param pointer to the memory block. Null pointer is permitted.\n    static void Free(void *ptr);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// CrtAllocator\n\n//! C-runtime library allocator.\n/*! This class is just wrapper for standard C library memory routines.\n    \\note implements Allocator concept\n*/\nclass CrtAllocator {\npublic:\n    static const bool kNeedFree = true;\n    void* Malloc(size_t size) { \n        if (size) //  behavior of malloc(0) is implementation defined.\n            return std::malloc(size);\n        else\n            return NULL; // standardize to returning NULL.\n    }\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        (void)originalSize;\n        if (newSize == 0) {\n            std::free(originalPtr);\n            return NULL;\n        }\n        return std::realloc(originalPtr, newSize);\n    }\n    static void Free(void *ptr) { std::free(ptr); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// MemoryPoolAllocator\n\n//! Default memory allocator used by the parser and DOM.\n/*! This allocator allocate memory blocks from pre-allocated memory chunks. \n\n    It does not free memory blocks. And Realloc() only allocate new memory.\n\n    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.\n\n    User may also supply a buffer as the first chunk.\n\n    If the user-buffer is full then additional chunks are allocated by BaseAllocator.\n\n    The user-buffer is not deallocated by this allocator.\n\n    \\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.\n    \\note implements Allocator concept\n*/\ntemplate <typename BaseAllocator = CrtAllocator>\nclass MemoryPoolAllocator {\npublic:\n    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)\n\n    //! Constructor with chunkSize.\n    /*! \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : \n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n    }\n\n    //! Constructor with user-supplied buffer.\n    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.\n\n        The user buffer will not be deallocated when this allocator is destructed.\n\n        \\param buffer User supplied buffer.\n        \\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).\n        \\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.\n        \\param baseAllocator The allocator for allocating memory chunks.\n    */\n    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :\n        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)\n    {\n        RAPIDJSON_ASSERT(buffer != 0);\n        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));\n        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);\n        chunkHead_->capacity = size - sizeof(ChunkHeader);\n        chunkHead_->size = 0;\n        chunkHead_->next = 0;\n    }\n\n    //! Destructor.\n    /*! This deallocates all memory chunks, excluding the user-supplied buffer.\n    */\n    ~MemoryPoolAllocator() {\n        Clear();\n        RAPIDJSON_DELETE(ownBaseAllocator_);\n    }\n\n    //! Deallocates all memory chunks, excluding the user-supplied buffer.\n    void Clear() {\n        while (chunkHead_ && chunkHead_ != userBuffer_) {\n            ChunkHeader* next = chunkHead_->next;\n            baseAllocator_->Free(chunkHead_);\n            chunkHead_ = next;\n        }\n        if (chunkHead_ && chunkHead_ == userBuffer_)\n            chunkHead_->size = 0; // Clear user buffer\n    }\n\n    //! Computes the total capacity of allocated memory chunks.\n    /*! \\return total capacity in bytes.\n    */\n    size_t Capacity() const {\n        size_t capacity = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            capacity += c->capacity;\n        return capacity;\n    }\n\n    //! Computes the memory blocks allocated.\n    /*! \\return total used bytes.\n    */\n    size_t Size() const {\n        size_t size = 0;\n        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)\n            size += c->size;\n        return size;\n    }\n\n    //! Allocates a memory block. (concept Allocator)\n    void* Malloc(size_t size) {\n        if (!size)\n            return NULL;\n\n        size = RAPIDJSON_ALIGN(size);\n        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)\n            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))\n                return NULL;\n\n        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;\n        chunkHead_->size += size;\n        return buffer;\n    }\n\n    //! Resizes a memory block (concept Allocator)\n    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {\n        if (originalPtr == 0)\n            return Malloc(newSize);\n\n        if (newSize == 0)\n            return NULL;\n\n        originalSize = RAPIDJSON_ALIGN(originalSize);\n        newSize = RAPIDJSON_ALIGN(newSize);\n\n        // Do not shrink if new size is smaller than original\n        if (originalSize >= newSize)\n            return originalPtr;\n\n        // Simply expand it if it is the last allocation and there is sufficient space\n        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {\n            size_t increment = static_cast<size_t>(newSize - originalSize);\n            if (chunkHead_->size + increment <= chunkHead_->capacity) {\n                chunkHead_->size += increment;\n                return originalPtr;\n            }\n        }\n\n        // Realloc process: allocate and copy memory, do not free original buffer.\n        if (void* newBuffer = Malloc(newSize)) {\n            if (originalSize)\n                std::memcpy(newBuffer, originalPtr, originalSize);\n            return newBuffer;\n        }\n        else\n            return NULL;\n    }\n\n    //! Frees a memory block (concept Allocator)\n    static void Free(void *ptr) { (void)ptr; } // Do nothing\n\nprivate:\n    //! Copy constructor is not permitted.\n    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;\n    //! Copy assignment operator is not permitted.\n    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;\n\n    //! Creates a new chunk.\n    /*! \\param capacity Capacity of the chunk in bytes.\n        \\return true if success.\n    */\n    bool AddChunk(size_t capacity) {\n        if (!baseAllocator_)\n            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());\n        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {\n            chunk->capacity = capacity;\n            chunk->size = 0;\n            chunk->next = chunkHead_;\n            chunkHead_ =  chunk;\n            return true;\n        }\n        else\n            return false;\n    }\n\n    static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.\n\n    //! Chunk header for perpending to each chunk.\n    /*! Chunks are stored as a singly linked list.\n    */\n    struct ChunkHeader {\n        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).\n        size_t size;        //!< Current size of allocated memory in bytes.\n        ChunkHeader *next;  //!< Next chunk in the linked list.\n    };\n\n    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.\n    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.\n    void *userBuffer_;          //!< User supplied buffer.\n    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.\n    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/document.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_DOCUMENT_H_\n#define RAPIDJSON_DOCUMENT_H_\n\n/*! \\file document.h */\n\n#include \"reader.h\"\n#include \"internal/meta.h\"\n#include \"internal/strfunc.h\"\n#include \"memorystream.h\"\n#include \"encodedstream.h\"\n#include <new>      // placement new\n#include <limits>\n\nRAPIDJSON_DIAG_PUSH\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\nRAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_OFF(effc++)\n#if __GNUC__ >= 6\nRAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions\n#endif\n#endif // __GNUC__\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n#include <iterator> // std::iterator, std::random_access_iterator_tag\n#endif\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n// Forward declaration.\ntemplate <typename Encoding, typename Allocator>\nclass GenericValue;\n\ntemplate <typename Encoding, typename Allocator, typename StackAllocator>\nclass GenericDocument;\n\n//! Name-value pair in a JSON object value.\n/*!\n    This class was internal to GenericValue. It used to be a inner struct.\n    But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.\n    https://code.google.com/p/rapidjson/issues/detail?id=64\n*/\ntemplate <typename Encoding, typename Allocator> \nstruct GenericMember { \n    GenericValue<Encoding, Allocator> name;     //!< name of member (must be a string)\n    GenericValue<Encoding, Allocator> value;    //!< value of member.\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericMemberIterator\n\n#ifndef RAPIDJSON_NOMEMBERITERATORCLASS\n\n//! (Constant) member iterator for a JSON object value\n/*!\n    \\tparam Const Is this a constant iterator?\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n\n    This class implements a Random Access Iterator for GenericMember elements\n    of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].\n\n    \\note This iterator implementation is mainly intended to avoid implicit\n        conversions from iterator values to \\c NULL,\n        e.g. from GenericValue::FindMember.\n\n    \\note Define \\c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a\n        pointer-based implementation, if your platform doesn't provide\n        the C++ <iterator> header.\n\n    \\see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator\n */\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator\n    : public std::iterator<std::random_access_iterator_tag\n        , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {\n\n    friend class GenericValue<Encoding,Allocator>;\n    template <bool, typename, typename> friend class GenericMemberIterator;\n\n    typedef GenericMember<Encoding,Allocator> PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;\n\npublic:\n    //! Iterator type itself\n    typedef GenericMemberIterator Iterator;\n    //! Constant iterator type\n    typedef GenericMemberIterator<true,Encoding,Allocator>  ConstIterator;\n    //! Non-constant iterator type\n    typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;\n\n    //! Pointer to (const) GenericMember\n    typedef typename BaseType::pointer         Pointer;\n    //! Reference to (const) GenericMember\n    typedef typename BaseType::reference       Reference;\n    //! Signed integer type (e.g. \\c ptrdiff_t)\n    typedef typename BaseType::difference_type DifferenceType;\n\n    //! Default constructor (singular value)\n    /*! Creates an iterator pointing to no element.\n        \\note All operations, except for comparisons, are undefined on such values.\n     */\n    GenericMemberIterator() : ptr_() {}\n\n    //! Iterator conversions to more const\n    /*!\n        \\param it (Non-const) iterator to copy from\n\n        Allows the creation of an iterator from another GenericMemberIterator\n        that is \"less const\".  Especially, creating a non-constant iterator\n        from a constant iterator are disabled:\n        \\li const -> non-const (not ok)\n        \\li const -> const (ok)\n        \\li non-const -> const (ok)\n        \\li non-const -> non-const (ok)\n\n        \\note If the \\c Const template parameter is already \\c false, this\n            constructor effectively defines a regular copy-constructor.\n            Otherwise, the copy constructor is implicitly defined.\n    */\n    GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}\n    Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }\n\n    //! @name stepping\n    //@{\n    Iterator& operator++(){ ++ptr_; return *this; }\n    Iterator& operator--(){ --ptr_; return *this; }\n    Iterator  operator++(int){ Iterator old(*this); ++ptr_; return old; }\n    Iterator  operator--(int){ Iterator old(*this); --ptr_; return old; }\n    //@}\n\n    //! @name increment/decrement\n    //@{\n    Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }\n    Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }\n\n    Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }\n    Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }\n    //@}\n\n    //! @name relations\n    //@{\n    bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }\n    bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }\n    bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }\n    bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }\n    bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }\n    bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }\n    //@}\n\n    //! @name dereference\n    //@{\n    Reference operator*() const { return *ptr_; }\n    Pointer   operator->() const { return ptr_; }\n    Reference operator[](DifferenceType n) const { return ptr_[n]; }\n    //@}\n\n    //! Distance\n    DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }\n\nprivate:\n    //! Internal constructor from plain pointer\n    explicit GenericMemberIterator(Pointer p) : ptr_(p) {}\n\n    Pointer ptr_; //!< raw pointer\n};\n\n#else // RAPIDJSON_NOMEMBERITERATORCLASS\n\n// class-based member iterator implementation disabled, use plain pointers\n\ntemplate <bool Const, typename Encoding, typename Allocator>\nstruct GenericMemberIterator;\n\n//! non-const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nstruct GenericMemberIterator<false,Encoding,Allocator> {\n    //! use plain pointer as iterator type\n    typedef GenericMember<Encoding,Allocator>* Iterator;\n};\n//! const GenericMemberIterator\ntemplate <typename Encoding, typename Allocator>\nstruct GenericMemberIterator<true,Encoding,Allocator> {\n    //! use plain const pointer as iterator type\n    typedef const GenericMember<Encoding,Allocator>* Iterator;\n};\n\n#endif // RAPIDJSON_NOMEMBERITERATORCLASS\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericStringRef\n\n//! Reference to a constant string (not taking a copy)\n/*!\n    \\tparam CharType character type of the string\n\n    This helper class is used to automatically infer constant string\n    references for string literals, especially from \\c const \\b (!)\n    character arrays.\n\n    The main use is for creating JSON string values without copying the\n    source string via an \\ref Allocator.  This requires that the referenced\n    string pointers have a sufficient lifetime, which exceeds the lifetime\n    of the associated GenericValue.\n\n    \\b Example\n    \\code\n    Value v(\"foo\");   // ok, no need to copy & calculate length\n    const char foo[] = \"foo\";\n    v.SetString(foo); // ok\n\n    const char* bar = foo;\n    // Value x(bar); // not ok, can't rely on bar's lifetime\n    Value x(StringRef(bar)); // lifetime explicitly guaranteed by user\n    Value y(StringRef(bar, 3));  // ok, explicitly pass length\n    \\endcode\n\n    \\see StringRef, GenericValue::SetString\n*/\ntemplate<typename CharType>\nstruct GenericStringRef {\n    typedef CharType Ch; //!< character type of the string\n\n    //! Create string reference from \\c const character array\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        This constructor implicitly creates a constant string reference from\n        a \\c const character array.  It has better performance than\n        \\ref StringRef(const CharType*) by inferring the string \\ref length\n        from the array length, and also supports strings containing null\n        characters.\n\n        \\tparam N length of the string, automatically inferred\n\n        \\param str Constant character array, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note Constant complexity.\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n#endif\n    template<SizeType N>\n    GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT\n        : s(str), length(N-1) {}\n\n    //! Explicitly create string reference from \\c const character pointer\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        This constructor can be used to \\b explicitly  create a reference to\n        a constant string pointer.\n\n        \\see StringRef(const CharType*)\n\n        \\param str Constant character pointer, lifetime assumed to be longer\n            than the use of the string in e.g. a GenericValue\n\n        \\post \\ref s == str\n\n        \\note There is a hidden, private overload to disallow references to\n            non-const character arrays to be created via this constructor.\n            By this, e.g. function-scope arrays used to be filled via\n            \\c snprintf are excluded from consideration.\n            In such cases, the referenced string should be \\b copied to the\n            GenericValue instead.\n     */\n#endif\n    explicit GenericStringRef(const CharType* str)\n        : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }\n\n    //! Create constant string reference from pointer and length\n#ifndef __clang__ // -Wdocumentation\n    /*! \\param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n        \\param len length of the string, excluding the trailing NULL terminator\n\n        \\post \\ref s == str && \\ref length == len\n        \\note Constant complexity.\n     */\n#endif\n    GenericStringRef(const CharType* str, SizeType len)\n        : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }\n\n    GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}\n\n    GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; }\n\n    //! implicit conversion to plain CharType pointer\n    operator const Ch *() const { return s; }\n\n    const Ch* const s; //!< plain CharType pointer\n    const SizeType length; //!< length of the string (excluding the trailing NULL terminator)\n\nprivate:\n    //! Disallow construction from non-const array\n    template<SizeType N>\n    GenericStringRef(CharType (&str)[N]) /* = delete */;\n};\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n    \\tparam CharType Character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n\n    \\see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str) {\n    return GenericStringRef<CharType>(str, internal::StrLen(str));\n}\n\n//! Mark a character pointer as constant string\n/*! Mark a plain character pointer as a \"string literal\".  This function\n    can be used to avoid copying a character string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    This version has better performance with supplied length, and also\n    supports string containing null characters.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\param length The length of source string.\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {\n    return GenericStringRef<CharType>(str, SizeType(length));\n}\n\n#if RAPIDJSON_HAS_STDSTRING\n//! Mark a string object as constant string\n/*! Mark a string object (e.g. \\c std::string) as a \"string literal\".\n    This function can be used to avoid copying a string to be referenced as a\n    value in a JSON GenericValue object, if the string's lifetime is known\n    to be valid long enough.\n\n    \\tparam CharType character type of the string\n    \\param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue\n    \\return GenericStringRef string reference object\n    \\relatesalso GenericStringRef\n    \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n*/\ntemplate<typename CharType>\ninline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {\n    return GenericStringRef<CharType>(str.data(), SizeType(str.size()));\n}\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue type traits\nnamespace internal {\n\ntemplate <typename T, typename Encoding = void, typename Allocator = void>\nstruct IsGenericValueImpl : FalseType {};\n\n// select candidates according to nested encoding and allocator types\ntemplate <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>\n    : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};\n\n// helper to match arbitrary GenericValue instantiations, including derived classes\ntemplate <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// TypeHelper\n\nnamespace internal {\n\ntemplate <typename ValueType, typename T>\nstruct TypeHelper {};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, bool> {\n    static bool Is(const ValueType& v) { return v.IsBool(); }\n    static bool Get(const ValueType& v) { return v.GetBool(); }\n    static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }\n    static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, int> {\n    static bool Is(const ValueType& v) { return v.IsInt(); }\n    static int Get(const ValueType& v) { return v.GetInt(); }\n    static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }\n    static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, unsigned> {\n    static bool Is(const ValueType& v) { return v.IsUint(); }\n    static unsigned Get(const ValueType& v) { return v.GetUint(); }\n    static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }\n    static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, int64_t> {\n    static bool Is(const ValueType& v) { return v.IsInt64(); }\n    static int64_t Get(const ValueType& v) { return v.GetInt64(); }\n    static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }\n    static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, uint64_t> {\n    static bool Is(const ValueType& v) { return v.IsUint64(); }\n    static uint64_t Get(const ValueType& v) { return v.GetUint64(); }\n    static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }\n    static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, double> {\n    static bool Is(const ValueType& v) { return v.IsDouble(); }\n    static double Get(const ValueType& v) { return v.GetDouble(); }\n    static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }\n    static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, float> {\n    static bool Is(const ValueType& v) { return v.IsFloat(); }\n    static float Get(const ValueType& v) { return v.GetFloat(); }\n    static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }\n    static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, const typename ValueType::Ch*> {\n    typedef const typename ValueType::Ch* StringType;\n    static bool Is(const ValueType& v) { return v.IsString(); }\n    static StringType Get(const ValueType& v) { return v.GetString(); }\n    static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }\n    static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }\n};\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {\n    typedef std::basic_string<typename ValueType::Ch> StringType;\n    static bool Is(const ValueType& v) { return v.IsString(); }\n    static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }\n    static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }\n};\n#endif\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::Array> {\n    typedef typename ValueType::Array ArrayType;\n    static bool Is(const ValueType& v) { return v.IsArray(); }\n    static ArrayType Get(ValueType& v) { return v.GetArray(); }\n    static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }\n    static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::ConstArray> {\n    typedef typename ValueType::ConstArray ArrayType;\n    static bool Is(const ValueType& v) { return v.IsArray(); }\n    static ArrayType Get(const ValueType& v) { return v.GetArray(); }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::Object> {\n    typedef typename ValueType::Object ObjectType;\n    static bool Is(const ValueType& v) { return v.IsObject(); }\n    static ObjectType Get(ValueType& v) { return v.GetObject(); }\n    static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }\n    static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }\n};\n\ntemplate<typename ValueType> \nstruct TypeHelper<ValueType, typename ValueType::ConstObject> {\n    typedef typename ValueType::ConstObject ObjectType;\n    static bool Is(const ValueType& v) { return v.IsObject(); }\n    static ObjectType Get(const ValueType& v) { return v.GetObject(); }\n};\n\n} // namespace internal\n\n// Forward declarations\ntemplate <bool, typename> class GenericArray;\ntemplate <bool, typename> class GenericObject;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericValue\n\n//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.\n/*!\n    A JSON value can be one of 7 types. This class is a variant type supporting\n    these types.\n\n    Use the Value if UTF8 and default allocator\n\n    \\tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)\n    \\tparam Allocator   Allocator type for allocating memory of object, array and string.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<> > \nclass GenericValue {\npublic:\n    //! Name-value pair in an object.\n    typedef GenericMember<Encoding, Allocator> Member;\n    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.\n    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.\n    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.\n    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string\n    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.\n    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.\n    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.\n    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.\n    typedef GenericArray<false, ValueType> Array;\n    typedef GenericArray<true, ValueType> ConstArray;\n    typedef GenericObject<false, ValueType> Object;\n    typedef GenericObject<true, ValueType> ConstObject;\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor creates a null value.\n    GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {\n        rhs.data_.f.flags = kNullFlag; // give up contents\n    }\n#endif\n\nprivate:\n    //! Copy constructor is not permitted.\n    GenericValue(const GenericValue& rhs);\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Moving from a GenericDocument is not permitted.\n    template <typename StackAllocator>\n    GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);\n\n    //! Move assignment from a GenericDocument is not permitted.\n    template <typename StackAllocator>\n    GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);\n#endif\n\npublic:\n\n    //! Constructor with JSON value type.\n    /*! This creates a Value of specified type with default content.\n        \\param type Type of the value.\n        \\note Default content for number is zero.\n    */\n    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {\n        static const uint16_t defaultFlags[7] = {\n            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,\n            kNumberAnyFlag\n        };\n        RAPIDJSON_ASSERT(type <= kNumberType);\n        data_.f.flags = defaultFlags[type];\n\n        // Use ShortString to store empty string.\n        if (type == kStringType)\n            data_.ss.SetLength(0);\n    }\n\n    //! Explicit copy constructor (with allocator)\n    /*! Creates a copy of a Value by using the given Allocator\n        \\tparam SourceAllocator allocator of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().\n        \\see CopyFrom()\n    */\n    template< typename SourceAllocator >\n    GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);\n\n    //! Constructor for boolean value.\n    /*! \\param b Boolean value\n        \\note This constructor is limited to \\em real boolean values and rejects\n            implicitly converted types like arbitrary pointers.  Use an explicit cast\n            to \\c bool, if you want to construct a boolean JSON value in such cases.\n     */\n#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen\n    template <typename T>\n    explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT  // See #472\n#else\n    explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT\n#endif\n        : data_() {\n            // safe-guard against failing SFINAE\n            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));\n            data_.f.flags = b ? kTrueFlag : kFalseFlag;\n    }\n\n    //! Constructor for int value.\n    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.i64 = i;\n        data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;\n    }\n\n    //! Constructor for unsigned value.\n    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.u64 = u; \n        data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);\n    }\n\n    //! Constructor for int64_t value.\n    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.i64 = i64;\n        data_.f.flags = kNumberInt64Flag;\n        if (i64 >= 0) {\n            data_.f.flags |= kNumberUint64Flag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n                data_.f.flags |= kUintFlag;\n            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n                data_.f.flags |= kIntFlag;\n        }\n        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            data_.f.flags |= kIntFlag;\n    }\n\n    //! Constructor for uint64_t value.\n    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {\n        data_.n.u64 = u64;\n        data_.f.flags = kNumberUint64Flag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))\n            data_.f.flags |= kInt64Flag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))\n            data_.f.flags |= kUintFlag;\n        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))\n            data_.f.flags |= kIntFlag;\n    }\n\n    //! Constructor for double value.\n    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }\n\n    //! Constructor for constant string (i.e. do not make a copy of string)\n    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }\n\n    //! Constructor for copy-string (i.e. do make a copy of string)\n    GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor for copy-string from a string object (i.e. do make a copy of string)\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }\n#endif\n\n    //! Constructor for Array.\n    /*!\n        \\param a An array obtained by \\c GetArray().\n        \\note \\c Array is always pass-by-value.\n        \\note the source array is moved into this value and the sourec array becomes empty.\n    */\n    GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {\n        a.value_.data_ = Data();\n        a.value_.data_.f.flags = kArrayFlag;\n    }\n\n    //! Constructor for Object.\n    /*!\n        \\param o An object obtained by \\c GetObject().\n        \\note \\c Object is always pass-by-value.\n        \\note the source object is moved into this value and the sourec object becomes empty.\n    */\n    GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {\n        o.value_.data_ = Data();\n        o.value_.data_.f.flags = kObjectFlag;\n    }\n\n    //! Destructor.\n    /*! Need to destruct elements of array, members of object, or copy-string.\n    */\n    ~GenericValue() {\n        if (Allocator::kNeedFree) { // Shortcut by Allocator's trait\n            switch(data_.f.flags) {\n            case kArrayFlag:\n                {\n                    GenericValue* e = GetElementsPointer();\n                    for (GenericValue* v = e; v != e + data_.a.size; ++v)\n                        v->~GenericValue();\n                    Allocator::Free(e);\n                }\n                break;\n\n            case kObjectFlag:\n                for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n                    m->~Member();\n                Allocator::Free(GetMembersPointer());\n                break;\n\n            case kCopyStringFlag:\n                Allocator::Free(const_cast<Ch*>(GetStringPointer()));\n                break;\n\n            default:\n                break;  // Do nothing for other types.\n            }\n        }\n    }\n\n    //@}\n\n    //!@name Assignment operators\n    //@{\n\n    //! Assignment with move semantics.\n    /*! \\param rhs Source of the assignment. It will become a null value after assignment.\n    */\n    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        RAPIDJSON_ASSERT(this != &rhs);\n        this->~GenericValue();\n        RawAssign(rhs);\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {\n        return *this = rhs.Move();\n    }\n#endif\n\n    //! Assignment of constant string reference (no copy)\n    /*! \\param str Constant string reference to be assigned\n        \\note This overload is needed to avoid clashes with the generic primitive type assignment overload below.\n        \\see GenericStringRef, operator=(T)\n    */\n    GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {\n        GenericValue s(str);\n        return *this = s;\n    }\n\n    //! Assignment with primitive types.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value The value to be assigned.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref SetString(const Ch*, Allocator&) (for copying) or\n            \\ref StringRef() (to explicitly mark the pointer as constant) instead.\n            All other pointer types would implicitly convert to \\c bool,\n            use \\ref SetBool() instead.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))\n    operator=(T value) {\n        GenericValue v(value);\n        return *this = v;\n    }\n\n    //! Deep-copy assignment from Value\n    /*! Assigns a \\b copy of the Value to the current Value object\n        \\tparam SourceAllocator Allocator type of \\c rhs\n        \\param rhs Value to copy from (read-only)\n        \\param allocator Allocator to use for copying\n     */\n    template <typename SourceAllocator>\n    GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {\n        RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));\n        this->~GenericValue();\n        new (this) GenericValue(rhs, allocator);\n        return *this;\n    }\n\n    //! Exchange the contents of this value with those of other.\n    /*!\n        \\param other Another value.\n        \\note Constant complexity.\n    */\n    GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {\n        GenericValue temp;\n        temp.RawAssign(*this);\n        RawAssign(other);\n        other.RawAssign(temp);\n        return *this;\n    }\n\n    //! free-standing swap function helper\n    /*!\n        Helper function to enable support for common swap implementation pattern based on \\c std::swap:\n        \\code\n        void swap(MyClass& a, MyClass& b) {\n            using std::swap;\n            swap(a.value, b.value);\n            // ...\n        }\n        \\endcode\n        \\see Swap()\n     */\n    friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }\n\n    //! Prepare Value for move semantics\n    /*! \\return *this */\n    GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }\n    //@}\n\n    //!@name Equal-to and not-equal-to operators\n    //@{\n    //! Equal-to operator\n    /*!\n        \\note If an object contains duplicated named member, comparing equality with any object is always \\c false.\n        \\note Linear time complexity (number of all values in the subtree and total lengths of all strings).\n    */\n    template <typename SourceAllocator>\n    bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        typedef GenericValue<Encoding, SourceAllocator> RhsType;\n        if (GetType() != rhs.GetType())\n            return false;\n\n        switch (GetType()) {\n        case kObjectType: // Warning: O(n^2) inner-loop\n            if (data_.o.size != rhs.data_.o.size)\n                return false;           \n            for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {\n                typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);\n                if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)\n                    return false;\n            }\n            return true;\n            \n        case kArrayType:\n            if (data_.a.size != rhs.data_.a.size)\n                return false;\n            for (SizeType i = 0; i < data_.a.size; i++)\n                if ((*this)[i] != rhs[i])\n                    return false;\n            return true;\n\n        case kStringType:\n            return StringEqual(rhs);\n\n        case kNumberType:\n            if (IsDouble() || rhs.IsDouble()) {\n                double a = GetDouble();     // May convert from integer to double.\n                double b = rhs.GetDouble(); // Ditto\n                return a >= b && a <= b;    // Prevent -Wfloat-equal\n            }\n            else\n                return data_.n.u64 == rhs.data_.n.u64;\n\n        default:\n            return true;\n        }\n    }\n\n    //! Equal-to operator with const C-string pointer\n    bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Equal-to operator with string object\n    /*! \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n     */\n    bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }\n#endif\n\n    //! Equal-to operator with primitive types\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c double, \\c true, \\c false\n    */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }\n\n    //! Not-equal-to operator\n    /*! \\return !(*this == rhs)\n     */\n    template <typename SourceAllocator>\n    bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with const C-string pointer\n    bool operator!=(const Ch* rhs) const { return !(*this == rhs); }\n\n    //! Not-equal-to operator with arbitrary types\n    /*! \\return !(*this == rhs)\n     */\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }\n\n    //! Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return (rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }\n\n    //! Not-Equal-to operator with arbitrary types (symmetric version)\n    /*! \\return !(rhs == lhs)\n     */\n    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }\n    //@}\n\n    //!@name Type\n    //@{\n\n    Type GetType()  const { return static_cast<Type>(data_.f.flags & kTypeMask); }\n    bool IsNull()   const { return data_.f.flags == kNullFlag; }\n    bool IsFalse()  const { return data_.f.flags == kFalseFlag; }\n    bool IsTrue()   const { return data_.f.flags == kTrueFlag; }\n    bool IsBool()   const { return (data_.f.flags & kBoolFlag) != 0; }\n    bool IsObject() const { return data_.f.flags == kObjectFlag; }\n    bool IsArray()  const { return data_.f.flags == kArrayFlag; }\n    bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }\n    bool IsInt()    const { return (data_.f.flags & kIntFlag) != 0; }\n    bool IsUint()   const { return (data_.f.flags & kUintFlag) != 0; }\n    bool IsInt64()  const { return (data_.f.flags & kInt64Flag) != 0; }\n    bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }\n    bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }\n    bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }\n\n    // Checks whether a number can be losslessly converted to a double.\n    bool IsLosslessDouble() const {\n        if (!IsNumber()) return false;\n        if (IsUint64()) {\n            uint64_t u = GetUint64();\n            volatile double d = static_cast<double>(u);\n            return (d >= 0.0)\n                && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))\n                && (u == static_cast<uint64_t>(d));\n        }\n        if (IsInt64()) {\n            int64_t i = GetInt64();\n            volatile double d = static_cast<double>(i);\n            return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))\n                && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))\n                && (i == static_cast<int64_t>(d));\n        }\n        return true; // double, int, uint are always lossless\n    }\n\n    // Checks whether a number is a float (possible lossy).\n    bool IsFloat() const  {\n        if ((data_.f.flags & kDoubleFlag) == 0)\n            return false;\n        double d = GetDouble();\n        return d >= -3.4028234e38 && d <= 3.4028234e38;\n    }\n    // Checks whether a number can be losslessly converted to a float.\n    bool IsLosslessFloat() const {\n        if (!IsNumber()) return false;\n        double a = GetDouble();\n        if (a < static_cast<double>(-std::numeric_limits<float>::max())\n                || a > static_cast<double>(std::numeric_limits<float>::max()))\n            return false;\n        double b = static_cast<double>(static_cast<float>(a));\n        return a >= b && a <= b;    // Prevent -Wfloat-equal\n    }\n\n    //@}\n\n    //!@name Null\n    //@{\n\n    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }\n\n    //@}\n\n    //!@name Bool\n    //@{\n\n    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }\n    //!< Set boolean value\n    /*! \\post IsBool() == true */\n    GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }\n\n    //@}\n\n    //!@name Object\n    //@{\n\n    //! Set this value as an empty object.\n    /*! \\post IsObject() == true */\n    GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }\n\n    //! Get the number of members in the object.\n    SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }\n\n    //! Check whether the object is empty.\n    bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam T Either \\c Ch or \\c const \\c Ch (template used for disambiguation with \\ref operator[](SizeType))\n        \\note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.\n        Since 0.2, if the name is not correct, it will assert.\n        If user is unsure whether a member exists, user should use HasMember() first.\n        A better approach is to use FindMember().\n        \\note Linear time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {\n        GenericValue n(StringRef(name));\n        return (*this)[n];\n    }\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n    //! Get a value from an object associated with the name.\n    /*! \\pre IsObject() == true\n        \\tparam SourceAllocator Allocator of the \\c name value\n\n        \\note Compared to \\ref operator[](T*), this version is faster because it does not need a StrLen().\n        And it can also handle strings with embedded null characters.\n\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator member = FindMember(name);\n        if (member != MemberEnd())\n            return member->value;\n        else {\n            RAPIDJSON_ASSERT(false);    // see above note\n\n            // This will generate -Wexit-time-destructors in clang\n            // static GenericValue NullValue;\n            // return NullValue;\n\n            // Use static buffer and placement-new to prevent destruction\n            static char buffer[sizeof(GenericValue)];\n            return *new (buffer) GenericValue();\n        }\n    }\n    template <typename SourceAllocator>\n    const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Get a value from an object associated with name (string object).\n    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }\n    const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }\n#endif\n\n    //! Const member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }\n    //! Const \\em past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    ConstMemberIterator MemberEnd() const   { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }\n    //! Member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }\n    //! \\em Past-the-end member iterator\n    /*! \\pre IsObject() == true */\n    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }\n\n    //! Check whether a member exists in the object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Check whether a member exists in the object with string object.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }\n#endif\n\n    //! Check whether a member exists in the object with GenericValue name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Whether a member with that name exists.\n        \\note It is better to use FindMember() directly if you need the obtain the value as well.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }\n\n    //! Find member by name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    MemberIterator FindMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return FindMember(n);\n    }\n\n    ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n    //! Find member by name.\n    /*!\n        This version is faster because it does not need a StrLen(). It can also handle string with null character.\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n\n        \\note Earlier versions of Rapidjson returned a \\c NULL pointer, in case\n            the requested member doesn't exist. For consistency with e.g.\n            \\c std::map, this has been changed to MemberEnd() now.\n        \\note Linear time complexity.\n    */\n    template <typename SourceAllocator>\n    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n        MemberIterator member = MemberBegin();\n        for ( ; member != MemberEnd(); ++member)\n            if (name.StringEqual(member->name))\n                break;\n        return member;\n    }\n    template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Find member by string object name.\n    /*!\n        \\param name Member name to be searched.\n        \\pre IsObject() == true\n        \\return Iterator to member, if it exists.\n            Otherwise returns \\ref MemberEnd().\n    */\n    MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }\n    ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }\n#endif\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c name and \\c value will be transferred to this object on success.\n        \\pre  IsObject() && name.IsString()\n        \\post name.IsNull() && value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(name.IsString());\n\n        ObjectData& o = data_.o;\n        if (o.size >= o.capacity) {\n            if (o.capacity == 0) {\n                o.capacity = kDefaultObjectCapacity;\n                SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));\n            }\n            else {\n                SizeType oldCapacity = o.capacity;\n                o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5\n                SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));\n            }\n        }\n        Member* members = GetMembersPointer();\n        members[o.size].name.RawAssign(name);\n        members[o.size].value.RawAssign(value);\n        o.size++;\n        return *this;\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Add a string object as member (name-value pair) to the object.\n    /*! \\param name A string value as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {\n        GenericValue v(value, allocator);\n        return AddMember(name, v, allocator);\n    }\n#endif\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A string value as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(GenericValue& name, T value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {\n        return AddMember(name, value, allocator);\n    }\n    GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n\n    //! Add a member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value Value of any type.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this object on success.\n        \\pre  IsObject()\n        \\post value.IsNull()\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Add a constant string value as member (name-value pair) to the object.\n    /*! \\param name A constant string reference as name of member.\n        \\param value constant string reference as value of member.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n        \\note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.\n        \\note Amortized Constant time complexity.\n    */\n    GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {\n        GenericValue v(value);\n        return AddMember(name, v, allocator);\n    }\n\n    //! Add any primitive value as member (name-value pair) to the object.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param name A constant string reference as name of member.\n        \\param value Value of primitive type \\c T as value of member\n        \\param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\pre  IsObject()\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref AddMember(StringRefType, GenericValue&, Allocator&) or \\ref\n            AddMember(StringRefType, StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized Constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    AddMember(StringRefType name, T value, Allocator& allocator) {\n        GenericValue n(name);\n        return AddMember(n, value, allocator);\n    }\n\n    //! Remove all members in the object.\n    /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void RemoveAllMembers() {\n        RAPIDJSON_ASSERT(IsObject()); \n        for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)\n            m->~Member();\n        data_.o.size = 0;\n    }\n\n    //! Remove a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Linear time complexity.\n    */\n    bool RemoveMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return RemoveMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            RemoveMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    //! Remove a member in object by iterator.\n    /*! \\param m member iterator (obtained by FindMember() or MemberBegin()).\n        \\return the new iterator after removal.\n        \\note This function may reorder the object members. Use \\ref\n            EraseMember(ConstMemberIterator) if you need to preserve the\n            relative order of the remaining members.\n        \\note Constant time complexity.\n    */\n    MemberIterator RemoveMember(MemberIterator m) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(GetMembersPointer() != 0);\n        RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());\n\n        MemberIterator last(GetMembersPointer() + (data_.o.size - 1));\n        if (data_.o.size > 1 && m != last)\n            *m = *last; // Move the last one to this place\n        else\n            m->~Member(); // Only one left, just destroy\n        --data_.o.size;\n        return m;\n    }\n\n    //! Remove a member from an object by iterator.\n    /*! \\param pos iterator to the member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c pos < \\ref MemberEnd()\n        \\return Iterator following the removed element.\n            If the iterator \\c pos refers to the last element, the \\ref MemberEnd() iterator is returned.\n        \\note This function preserves the relative order of the remaining object\n            members. If you do not need this, use the more efficient \\ref RemoveMember(MemberIterator).\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator pos) {\n        return EraseMember(pos, pos +1);\n    }\n\n    //! Remove members in the range [first, last) from an object.\n    /*! \\param first iterator to the first member to remove\n        \\param last  iterator following the last member to remove\n        \\pre IsObject() == true && \\ref MemberBegin() <= \\c first <= \\c last <= \\ref MemberEnd()\n        \\return Iterator following the last removed element.\n        \\note This function preserves the relative order of the remaining object\n            members.\n        \\note Linear time complexity.\n    */\n    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {\n        RAPIDJSON_ASSERT(IsObject());\n        RAPIDJSON_ASSERT(data_.o.size > 0);\n        RAPIDJSON_ASSERT(GetMembersPointer() != 0);\n        RAPIDJSON_ASSERT(first >= MemberBegin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= MemberEnd());\n\n        MemberIterator pos = MemberBegin() + (first - MemberBegin());\n        for (MemberIterator itr = pos; itr != last; ++itr)\n            itr->~Member();\n        std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));\n        data_.o.size -= static_cast<SizeType>(last - first);\n        return pos;\n    }\n\n    //! Erase a member in object by its name.\n    /*! \\param name Name of member to be removed.\n        \\return Whether the member existed.\n        \\note Linear time complexity.\n    */\n    bool EraseMember(const Ch* name) {\n        GenericValue n(StringRef(name));\n        return EraseMember(n);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }\n#endif\n\n    template <typename SourceAllocator>\n    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {\n        MemberIterator m = FindMember(name);\n        if (m != MemberEnd()) {\n            EraseMember(m);\n            return true;\n        }\n        else\n            return false;\n    }\n\n    Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }\n    ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }\n\n    //@}\n\n    //!@name Array\n    //@{\n\n    //! Set this value as an empty array.\n    /*! \\post IsArray == true */\n    GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }\n\n    //! Get the number of elements in array.\n    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }\n\n    //! Get the capacity of array.\n    SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }\n\n    //! Check whether the array is empty.\n    bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }\n\n    //! Remove all elements in the array.\n    /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.\n        \\note Linear time complexity.\n    */\n    void Clear() {\n        RAPIDJSON_ASSERT(IsArray()); \n        GenericValue* e = GetElementsPointer();\n        for (GenericValue* v = e; v != e + data_.a.size; ++v)\n            v->~GenericValue();\n        data_.a.size = 0;\n    }\n\n    //! Get an element from array by index.\n    /*! \\pre IsArray() == true\n        \\param index Zero-based index of element.\n        \\see operator[](T*)\n    */\n    GenericValue& operator[](SizeType index) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(index < data_.a.size);\n        return GetElementsPointer()[index];\n    }\n    const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }\n\n    //! Element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }\n    //! \\em Past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }\n    //! Constant element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }\n    //! Constant \\em past-the-end element iterator\n    /*! \\pre IsArray() == true */\n    ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }\n\n    //! Request the array to have enough capacity to store elements.\n    /*! \\param newCapacity  The capacity that the array at least need to have.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\note Linear time complexity.\n    */\n    GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (newCapacity > data_.a.capacity) {\n            SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));\n            data_.a.capacity = newCapacity;\n        }\n        return *this;\n    }\n\n    //! Append a GenericValue at the end of the array.\n    /*! \\param value        Value to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\post value.IsNull() == true\n        \\return The value itself for fluent API.\n        \\note The ownership of \\c value will be transferred to this array on success.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n    */\n    GenericValue& PushBack(GenericValue& value, Allocator& allocator) {\n        RAPIDJSON_ASSERT(IsArray());\n        if (data_.a.size >= data_.a.capacity)\n            Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);\n        GetElementsPointer()[data_.a.size++].RawAssign(value);\n        return *this;\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {\n        return PushBack(value, allocator);\n    }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n    //! Append a constant string reference at the end of the array.\n    /*! \\param value        Constant string reference to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n        \\note Amortized constant time complexity.\n        \\see GenericStringRef\n    */\n    GenericValue& PushBack(StringRefType value, Allocator& allocator) {\n        return (*this).template PushBack<StringRefType>(value, allocator);\n    }\n\n    //! Append a primitive value at the end of the array.\n    /*! \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t\n        \\param value Value of primitive type T to be appended.\n        \\param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().\n        \\pre IsArray() == true\n        \\return The value itself for fluent API.\n        \\note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.\n\n        \\note The source type \\c T explicitly disallows all pointer types,\n            especially (\\c const) \\ref Ch*.  This helps avoiding implicitly\n            referencing character strings with insufficient lifetime, use\n            \\ref PushBack(GenericValue&, Allocator&) or \\ref\n            PushBack(StringRefType, Allocator&).\n            All other pointer types would implicitly convert to \\c bool,\n            use an explicit cast instead, if needed.\n        \\note Amortized constant time complexity.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))\n    PushBack(T value, Allocator& allocator) {\n        GenericValue v(value);\n        return PushBack(v, allocator);\n    }\n\n    //! Remove the last element in the array.\n    /*!\n        \\note Constant time complexity.\n    */\n    GenericValue& PopBack() {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(!Empty());\n        GetElementsPointer()[--data_.a.size].~GenericValue();\n        return *this;\n    }\n\n    //! Remove an element of array by iterator.\n    /*!\n        \\param pos iterator to the element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c pos < \\ref End()\n        \\return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator pos) {\n        return Erase(pos, pos + 1);\n    }\n\n    //! Remove elements in the range [first, last) of the array.\n    /*!\n        \\param first iterator to the first element to remove\n        \\param last  iterator following the last element to remove\n        \\pre IsArray() == true && \\ref Begin() <= \\c first <= \\c last <= \\ref End()\n        \\return Iterator following the last removed element.\n        \\note Linear time complexity.\n    */\n    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {\n        RAPIDJSON_ASSERT(IsArray());\n        RAPIDJSON_ASSERT(data_.a.size > 0);\n        RAPIDJSON_ASSERT(GetElementsPointer() != 0);\n        RAPIDJSON_ASSERT(first >= Begin());\n        RAPIDJSON_ASSERT(first <= last);\n        RAPIDJSON_ASSERT(last <= End());\n        ValueIterator pos = Begin() + (first - Begin());\n        for (ValueIterator itr = pos; itr != last; ++itr)\n            itr->~GenericValue();       \n        std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));\n        data_.a.size -= static_cast<SizeType>(last - first);\n        return pos;\n    }\n\n    Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }\n    ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }\n\n    //@}\n\n    //!@name Number\n    //@{\n\n    int GetInt() const          { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag);   return data_.n.i.i;   }\n    unsigned GetUint() const    { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag);  return data_.n.u.u;   }\n    int64_t GetInt64() const    { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }\n    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }\n\n    //! Get the value as double type.\n    /*! \\note If the value is 64-bit integer type, it may lose precision. Use \\c IsLosslessDouble() to check whether the converison is lossless.\n    */\n    double GetDouble() const {\n        RAPIDJSON_ASSERT(IsNumber());\n        if ((data_.f.flags & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.\n        if ((data_.f.flags & kIntFlag) != 0)                   return data_.n.i.i; // int -> double\n        if ((data_.f.flags & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double\n        if ((data_.f.flags & kInt64Flag) != 0)                 return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)\n        RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0);  return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)\n    }\n\n    //! Get the value as float type.\n    /*! \\note If the value is 64-bit integer type, it may lose precision. Use \\c IsLosslessFloat() to check whether the converison is lossless.\n    */\n    float GetFloat() const {\n        return static_cast<float>(GetDouble());\n    }\n\n    GenericValue& SetInt(int i)             { this->~GenericValue(); new (this) GenericValue(i);    return *this; }\n    GenericValue& SetUint(unsigned u)       { this->~GenericValue(); new (this) GenericValue(u);    return *this; }\n    GenericValue& SetInt64(int64_t i64)     { this->~GenericValue(); new (this) GenericValue(i64);  return *this; }\n    GenericValue& SetUint64(uint64_t u64)   { this->~GenericValue(); new (this) GenericValue(u64);  return *this; }\n    GenericValue& SetDouble(double d)       { this->~GenericValue(); new (this) GenericValue(d);    return *this; }\n    GenericValue& SetFloat(float f)         { this->~GenericValue(); new (this) GenericValue(f);    return *this; }\n\n    //@}\n\n    //!@name String\n    //@{\n\n    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }\n\n    //! Get the length of string.\n    /*! Since rapidjson permits \"\\\\u0000\" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().\n    */\n    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }\n\n    //! Set this value as a string without copying source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string pointer. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == length\n        \\see SetString(StringRefType)\n    */\n    GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }\n\n    //! Set this value as a string without copying source string.\n    /*! \\param s source string reference\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() == s && GetStringLength() == s.length\n    */\n    GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }\n\n    //! Set this value as a string by copying from source string.\n    /*! This version has better performance with supplied length, and also support string containing null character.\n        \\param s source string. \n        \\param length The length of source string, excluding the trailing null terminator.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }\n\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string. \n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length\n    */\n    GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set this value as a string by copying from source string.\n    /*! \\param s source string.\n        \\param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().\n        \\return The value itself for fluent API.\n        \\post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }\n#endif\n\n    //@}\n\n    //!@name Array\n    //@{\n\n    //! Templated version for checking whether this value is type T.\n    /*!\n        \\tparam T Either \\c bool, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c double, \\c float, \\c const \\c char*, \\c std::basic_string<Ch>\n    */\n    template <typename T>\n    bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }\n\n    template <typename T>\n    T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }\n\n    template <typename T>\n    T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }\n\n    template<typename T>\n    ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }\n\n    template<typename T>\n    ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }\n\n    //@}\n\n    //! Generate events of this value to a Handler.\n    /*! This function adopts the GoF visitor pattern.\n        Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.\n        It can also be used to deep clone this value via GenericDocument, which is also a Handler.\n        \\tparam Handler type of handler.\n        \\param handler An object implementing concept Handler.\n    */\n    template <typename Handler>\n    bool Accept(Handler& handler) const {\n        switch(GetType()) {\n        case kNullType:     return handler.Null();\n        case kFalseType:    return handler.Bool(false);\n        case kTrueType:     return handler.Bool(true);\n\n        case kObjectType:\n            if (RAPIDJSON_UNLIKELY(!handler.StartObject()))\n                return false;\n            for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {\n                RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.\n                if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))\n                    return false;\n                if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))\n                    return false;\n            }\n            return handler.EndObject(data_.o.size);\n\n        case kArrayType:\n            if (RAPIDJSON_UNLIKELY(!handler.StartArray()))\n                return false;\n            for (const GenericValue* v = Begin(); v != End(); ++v)\n                if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))\n                    return false;\n            return handler.EndArray(data_.a.size);\n    \n        case kStringType:\n            return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);\n    \n        default:\n            RAPIDJSON_ASSERT(GetType() == kNumberType);\n            if (IsDouble())         return handler.Double(data_.n.d);\n            else if (IsInt())       return handler.Int(data_.n.i.i);\n            else if (IsUint())      return handler.Uint(data_.n.u.u);\n            else if (IsInt64())     return handler.Int64(data_.n.i64);\n            else                    return handler.Uint64(data_.n.u64);\n        }\n    }\n\nprivate:\n    template <typename, typename> friend class GenericValue;\n    template <typename, typename, typename> friend class GenericDocument;\n\n    enum {\n        kBoolFlag       = 0x0008,\n        kNumberFlag     = 0x0010,\n        kIntFlag        = 0x0020,\n        kUintFlag       = 0x0040,\n        kInt64Flag      = 0x0080,\n        kUint64Flag     = 0x0100,\n        kDoubleFlag     = 0x0200,\n        kStringFlag     = 0x0400,\n        kCopyFlag       = 0x0800,\n        kInlineStrFlag  = 0x1000,\n\n        // Initial flags of different types.\n        kNullFlag = kNullType,\n        kTrueFlag = kTrueType | kBoolFlag,\n        kFalseFlag = kFalseType | kBoolFlag,\n        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,\n        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,\n        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,\n        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,\n        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,\n        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,\n        kConstStringFlag = kStringType | kStringFlag,\n        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,\n        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,\n        kObjectFlag = kObjectType,\n        kArrayFlag = kArrayType,\n\n        kTypeMask = 0x07\n    };\n\n    static const SizeType kDefaultArrayCapacity = 16;\n    static const SizeType kDefaultObjectCapacity = 16;\n\n    struct Flag {\n#if RAPIDJSON_48BITPOINTER_OPTIMIZATION\n        char payload[sizeof(SizeType) * 2 + 6];     // 2 x SizeType + lower 48-bit pointer\n#elif RAPIDJSON_64BIT\n        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes\n#else\n        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes\n#endif\n        uint16_t flags;\n    };\n\n    struct String {\n        SizeType length;\n        SizeType hashcode;  //!< reserved\n        const Ch* str;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars\n    // (excluding the terminating zero) and store a value to determine the length of the contained\n    // string in the last character str[LenPos] by storing \"MaxSize - length\" there. If the string\n    // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as\n    // the string terminator as well. For getting the string length back from that value just use\n    // \"MaxSize - str[LenPos]\".\n    // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,\n    // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).\n    struct ShortString {\n        enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };\n        Ch str[MaxChars];\n\n        inline static bool Usable(SizeType len) { return                       (MaxSize >= len); }\n        inline void     SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize -  len); }\n        inline SizeType GetLength() const       { return  static_cast<SizeType>(MaxSize -  str[LenPos]); }\n    };  // at most as many bytes as \"String\" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    // By using proper binary layout, retrieval of different integer types do not need conversions.\n    union Number {\n#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN\n        struct I {\n            int i;\n            char padding[4];\n        }i;\n        struct U {\n            unsigned u;\n            char padding2[4];\n        }u;\n#else\n        struct I {\n            char padding[4];\n            int i;\n        }i;\n        struct U {\n            char padding2[4];\n            unsigned u;\n        }u;\n#endif\n        int64_t i64;\n        uint64_t u64;\n        double d;\n    };  // 8 bytes\n\n    struct ObjectData {\n        SizeType size;\n        SizeType capacity;\n        Member* members;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    struct ArrayData {\n        SizeType size;\n        SizeType capacity;\n        GenericValue* elements;\n    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode\n\n    union Data {\n        String s;\n        ShortString ss;\n        Number n;\n        ObjectData o;\n        ArrayData a;\n        Flag f;\n    };  // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n    RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }\n    RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }\n    RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }\n    RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }\n    RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }\n    RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }\n\n    // Initialize this value as array with initial data, without calling destructor.\n    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {\n        data_.f.flags = kArrayFlag;\n        if (count) {\n            GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));\n            SetElementsPointer(e);\n            std::memcpy(e, values, count * sizeof(GenericValue));\n        }\n        else\n            SetElementsPointer(0);\n        data_.a.size = data_.a.capacity = count;\n    }\n\n    //! Initialize this value as object with initial data, without calling destructor.\n    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {\n        data_.f.flags = kObjectFlag;\n        if (count) {\n            Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));\n            SetMembersPointer(m);\n            std::memcpy(m, members, count * sizeof(Member));\n        }\n        else\n            SetMembersPointer(0);\n        data_.o.size = data_.o.capacity = count;\n    }\n\n    //! Initialize this value as constant string, without calling destructor.\n    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {\n        data_.f.flags = kConstStringFlag;\n        SetStringPointer(s);\n        data_.s.length = s.length;\n    }\n\n    //! Initialize this value as copy string with initial data, without calling destructor.\n    void SetStringRaw(StringRefType s, Allocator& allocator) {\n        Ch* str = 0;\n        if (ShortString::Usable(s.length)) {\n            data_.f.flags = kShortStringFlag;\n            data_.ss.SetLength(s.length);\n            str = data_.ss.str;\n        } else {\n            data_.f.flags = kCopyStringFlag;\n            data_.s.length = s.length;\n            str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));\n            SetStringPointer(str);\n        }\n        std::memcpy(str, s, s.length * sizeof(Ch));\n        str[s.length] = '\\0';\n    }\n\n    //! Assignment without calling destructor\n    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {\n        data_ = rhs.data_;\n        // data_.f.flags = rhs.data_.f.flags;\n        rhs.data_.f.flags = kNullFlag;\n    }\n\n    template <typename SourceAllocator>\n    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {\n        RAPIDJSON_ASSERT(IsString());\n        RAPIDJSON_ASSERT(rhs.IsString());\n\n        const SizeType len1 = GetStringLength();\n        const SizeType len2 = rhs.GetStringLength();\n        if(len1 != len2) { return false; }\n\n        const Ch* const str1 = GetString();\n        const Ch* const str2 = rhs.GetString();\n        if(str1 == str2) { return true; } // fast path for constant string\n\n        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);\n    }\n\n    Data data_;\n};\n\n//! GenericValue with UTF8 encoding\ntypedef GenericValue<UTF8<> > Value;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericDocument \n\n//! A document for parsing JSON text as DOM.\n/*!\n    \\note implements Handler concept\n    \\tparam Encoding Encoding for both parsing and string storage.\n    \\tparam Allocator Allocator for allocating memory for the DOM\n    \\tparam StackAllocator Allocator for allocating memory for stack during parsing.\n    \\warning Although GenericDocument inherits from GenericValue, the API does \\b not provide any virtual functions, especially no virtual destructor.  To avoid memory leaks, do not \\c delete a GenericDocument object via a pointer to a GenericValue.\n*/\ntemplate <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>\nclass GenericDocument : public GenericValue<Encoding, Allocator> {\npublic:\n    typedef typename Encoding::Ch Ch;                       //!< Character type derived from Encoding.\n    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of the document.\n    typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.\n\n    //! Constructor\n    /*! Creates an empty document of specified type.\n        \\param type             Mandatory type of object to create.\n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :\n        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n    }\n\n    //! Constructor\n    /*! Creates an empty document which type is Null. \n        \\param allocator        Optional allocator for allocating memory.\n        \\param stackCapacity    Optional initial capacity of stack in bytes.\n        \\param stackAllocator   Optional allocator for allocating memory for stack.\n    */\n    GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : \n        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n        : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document\n          allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(std::move(rhs.stack_)),\n          parseResult_(rhs.parseResult_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n    }\n#endif\n\n    ~GenericDocument() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move assignment in C++11\n    GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT\n    {\n        // The cast to ValueType is necessary here, because otherwise it would\n        // attempt to call GenericValue's templated assignment operator.\n        ValueType::operator=(std::forward<ValueType>(rhs));\n\n        // Calling the destructor here would prematurely call stack_'s destructor\n        Destroy();\n\n        allocator_ = rhs.allocator_;\n        ownAllocator_ = rhs.ownAllocator_;\n        stack_ = std::move(rhs.stack_);\n        parseResult_ = rhs.parseResult_;\n\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.parseResult_ = ParseResult();\n\n        return *this;\n    }\n#endif\n\n    //! Exchange the contents of this document with those of another.\n    /*!\n        \\param rhs Another document.\n        \\note Constant complexity.\n        \\see GenericValue::Swap\n    */\n    GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {\n        ValueType::Swap(rhs);\n        stack_.Swap(rhs.stack_);\n        internal::Swap(allocator_, rhs.allocator_);\n        internal::Swap(ownAllocator_, rhs.ownAllocator_);\n        internal::Swap(parseResult_, rhs.parseResult_);\n        return *this;\n    }\n\n    //! free-standing swap function helper\n    /*!\n        Helper function to enable support for common swap implementation pattern based on \\c std::swap:\n        \\code\n        void swap(MyClass& a, MyClass& b) {\n            using std::swap;\n            swap(a.doc, b.doc);\n            // ...\n        }\n        \\endcode\n        \\see Swap()\n     */\n    friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }\n\n    //! Populate this document by a generator which produces SAX events.\n    /*! \\tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.\n        \\param g Generator functor which sends SAX events to the parameter.\n        \\return The document itself for fluent API.\n    */\n    template <typename Generator>\n    GenericDocument& Populate(Generator& g) {\n        ClearStackOnExit scope(*this);\n        if (g(*this)) {\n            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document\n        }\n        return *this;\n    }\n\n    //!@name Parse from stream\n    //!@{\n\n    //! Parse JSON text from an input stream (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam SourceEncoding Encoding of input stream\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename SourceEncoding, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(\n            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);\n        ClearStackOnExit scope(*this);\n        parseResult_ = reader.template Parse<parseFlags>(is, *this);\n        if (parseResult_) {\n            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object\n            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document\n        }\n        return *this;\n    }\n\n    //! Parse JSON text from an input stream\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags, typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<parseFlags, Encoding, InputStream>(is);\n    }\n\n    //! Parse JSON text from an input stream (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\param is Input stream to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <typename InputStream>\n    GenericDocument& ParseStream(InputStream& is) {\n        return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);\n    }\n    //!@}\n\n    //!@name Parse in-place from mutable string\n    //!@{\n\n    //! Parse JSON text from a mutable string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& ParseInsitu(Ch* str) {\n        GenericInsituStringStream<Encoding> s(str);\n        return ParseStream<parseFlags | kParseInsituFlag>(s);\n    }\n\n    //! Parse JSON text from a mutable string (with \\ref kParseDefaultFlags)\n    /*! \\param str Mutable zero-terminated string to be parsed.\n        \\return The document itself for fluent API.\n    */\n    GenericDocument& ParseInsitu(Ch* str) {\n        return ParseInsitu<kParseDefaultFlags>(str);\n    }\n    //!@}\n\n    //!@name Parse from read-only string\n    //!@{\n\n    //! Parse JSON text from a read-only string (with Encoding conversion)\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\tparam SourceEncoding Transcoding from input Encoding\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const typename SourceEncoding::Ch* str) {\n        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n        GenericStringStream<SourceEncoding> s(str);\n        return ParseStream<parseFlags, SourceEncoding>(s);\n    }\n\n    //! Parse JSON text from a read-only string\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag (must not contain \\ref kParseInsituFlag).\n        \\param str Read-only zero-terminated string to be parsed.\n    */\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<parseFlags, Encoding>(str);\n    }\n\n    //! Parse JSON text from a read-only string (with \\ref kParseDefaultFlags)\n    /*! \\param str Read-only zero-terminated string to be parsed.\n    */\n    GenericDocument& Parse(const Ch* str) {\n        return Parse<kParseDefaultFlags>(str);\n    }\n\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {\n        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));\n        MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));\n        EncodedInputStream<SourceEncoding, MemoryStream> is(ms);\n        ParseStream<parseFlags, SourceEncoding>(is);\n        return *this;\n    }\n\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const Ch* str, size_t length) {\n        return Parse<parseFlags, Encoding>(str, length);\n    }\n    \n    GenericDocument& Parse(const Ch* str, size_t length) {\n        return Parse<kParseDefaultFlags>(str, length);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    template <unsigned parseFlags, typename SourceEncoding>\n    GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {\n        // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)\n        return Parse<parseFlags, SourceEncoding>(str.c_str());\n    }\n\n    template <unsigned parseFlags>\n    GenericDocument& Parse(const std::basic_string<Ch>& str) {\n        return Parse<parseFlags, Encoding>(str.c_str());\n    }\n\n    GenericDocument& Parse(const std::basic_string<Ch>& str) {\n        return Parse<kParseDefaultFlags>(str);\n    }\n#endif // RAPIDJSON_HAS_STDSTRING    \n\n    //!@}\n\n    //!@name Handling parse errors\n    //!@{\n\n    //! Whether a parse error has occured in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n\n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseError() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\n    //! Implicit conversion to get the last parse result\n#ifndef __clang // -Wdocumentation\n    /*! \\return \\ref ParseResult of the last parse operation\n\n        \\code\n          Document doc;\n          ParseResult ok = doc.Parse(json);\n          if (!ok)\n            printf( \"JSON parse error: %s (%u)\\n\", GetParseError_En(ok.Code()), ok.Offset());\n        \\endcode\n     */\n#endif\n    operator ParseResult() const { return parseResult_; }\n    //!@}\n\n    //! Get the allocator of this document.\n    Allocator& GetAllocator() {\n        RAPIDJSON_ASSERT(allocator_);\n        return *allocator_;\n    }\n\n    //! Get the capacity of stack in bytes.\n    size_t GetStackCapacity() const { return stack_.GetCapacity(); }\n\nprivate:\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}\n        ~ClearStackOnExit() { d_.ClearStack(); }\n    private:\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n        GenericDocument& d_;\n    };\n\n    // callers of the following private Handler functions\n    // template <typename,typename,typename> friend class GenericReader; // for parsing\n    template <typename, typename> friend class GenericValue; // for deep copying\n\npublic:\n    // Implementation of Handler\n    bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }\n    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }\n    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }\n    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy) { \n        if (copy) \n            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n        else\n            new (stack_.template Push<ValueType>()) ValueType(str, length);\n        return true;\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy) { \n        if (copy) \n            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());\n        else\n            new (stack_.template Push<ValueType>()) ValueType(str, length);\n        return true;\n    }\n\n    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }\n    \n    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }\n\n    bool EndObject(SizeType memberCount) {\n        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);\n        stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());\n        return true;\n    }\n\n    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }\n    \n    bool EndArray(SizeType elementCount) {\n        ValueType* elements = stack_.template Pop<ValueType>(elementCount);\n        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());\n        return true;\n    }\n\nprivate:\n    //! Prohibit copying\n    GenericDocument(const GenericDocument&);\n    //! Prohibit assignment\n    GenericDocument& operator=(const GenericDocument&);\n\n    void ClearStack() {\n        if (Allocator::kNeedFree)\n            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)\n                (stack_.template Pop<ValueType>(1))->~ValueType();\n        else\n            stack_.Clear();\n        stack_.ShrinkToFit();\n    }\n\n    void Destroy() {\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    static const size_t kDefaultStackCapacity = 1024;\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    internal::Stack<StackAllocator> stack_;\n    ParseResult parseResult_;\n};\n\n//! GenericDocument with UTF8 encoding\ntypedef GenericDocument<UTF8<> > Document;\n\n// defined here due to the dependency on GenericDocument\ntemplate <typename Encoding, typename Allocator>\ntemplate <typename SourceAllocator>\ninline\nGenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)\n{\n    switch (rhs.GetType()) {\n    case kObjectType:\n    case kArrayType: { // perform deep copy via SAX Handler\n            GenericDocument<Encoding,Allocator> d(&allocator);\n            rhs.Accept(d);\n            RawAssign(*d.stack_.template Pop<GenericValue>(1));\n        }\n        break;\n    case kStringType:\n        if (rhs.data_.f.flags == kConstStringFlag) {\n            data_.f.flags = rhs.data_.f.flags;\n            data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n        } else {\n            SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);\n        }\n        break;\n    default:\n        data_.f.flags = rhs.data_.f.flags;\n        data_  = *reinterpret_cast<const Data*>(&rhs.data_);\n        break;\n    }\n}\n\n//! Helper class for accessing Value of array type.\n/*!\n    Instance of this helper class is obtained by \\c GenericValue::GetArray().\n    In addition to all APIs for array type, it provides range-based for loop if \\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.\n*/\ntemplate <bool Const, typename ValueT>\nclass GenericArray {\npublic:\n    typedef GenericArray<true, ValueT> ConstArray;\n    typedef GenericArray<false, ValueT> Array;\n    typedef ValueT PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef ValueType* ValueIterator;  // This may be const or non-const iterator\n    typedef const ValueT* ConstValueIterator;\n    typedef typename ValueType::AllocatorType AllocatorType;\n    typedef typename ValueType::StringRefType StringRefType;\n\n    template <typename, typename>\n    friend class GenericValue;\n\n    GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}\n    GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }\n    ~GenericArray() {}\n\n    SizeType Size() const { return value_.Size(); }\n    SizeType Capacity() const { return value_.Capacity(); }\n    bool Empty() const { return value_.Empty(); }\n    void Clear() const { value_.Clear(); }\n    ValueType& operator[](SizeType index) const {  return value_[index]; }\n    ValueIterator Begin() const { return value_.Begin(); }\n    ValueIterator End() const { return value_.End(); }\n    GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }\n    GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }\n    GenericArray PopBack() const { value_.PopBack(); return *this; }\n    ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }\n    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }\n\n#if RAPIDJSON_HAS_CXX11_RANGE_FOR\n    ValueIterator begin() const { return value_.Begin(); }\n    ValueIterator end() const { return value_.End(); }\n#endif\n\nprivate:\n    GenericArray();\n    GenericArray(ValueType& value) : value_(value) {}\n    ValueType& value_;\n};\n\n//! Helper class for accessing Value of object type.\n/*!\n    Instance of this helper class is obtained by \\c GenericValue::GetObject().\n    In addition to all APIs for array type, it provides range-based for loop if \\c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.\n*/\ntemplate <bool Const, typename ValueT>\nclass GenericObject {\npublic:\n    typedef GenericObject<true, ValueT> ConstObject;\n    typedef GenericObject<false, ValueT> Object;\n    typedef ValueT PlainType;\n    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;\n    typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator;  // This may be const or non-const iterator\n    typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;\n    typedef typename ValueType::AllocatorType AllocatorType;\n    typedef typename ValueType::StringRefType StringRefType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename ValueType::Ch Ch;\n\n    template <typename, typename>\n    friend class GenericValue;\n\n    GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}\n    GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }\n    ~GenericObject() {}\n\n    SizeType MemberCount() const { return value_.MemberCount(); }\n    bool ObjectEmpty() const { return value_.ObjectEmpty(); }\n    template <typename T> ValueType& operator[](T* name) const { return value_[name]; }\n    template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }\n#if RAPIDJSON_HAS_STDSTRING\n    ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }\n#endif\n    MemberIterator MemberBegin() const { return value_.MemberBegin(); }\n    MemberIterator MemberEnd() const { return value_.MemberEnd(); }\n    bool HasMember(const Ch* name) const { return value_.HasMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }\n#endif\n    template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }\n    MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }\n    template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }\n#endif\n    GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#if RAPIDJSON_HAS_STDSTRING\n    GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#endif\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }\n    void RemoveAllMembers() { return value_.RemoveAllMembers(); }\n    bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }\n#endif\n    template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }\n    MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }\n    MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }\n    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }\n    bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }\n#if RAPIDJSON_HAS_STDSTRING\n    bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }\n#endif\n    template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }\n\n#if RAPIDJSON_HAS_CXX11_RANGE_FOR\n    MemberIterator begin() const { return value_.MemberBegin(); }\n    MemberIterator end() const { return value_.MemberEnd(); }\n#endif\n\nprivate:\n    GenericObject();\n    GenericObject(ValueType& value) : value_(value) {}\n    ValueType& value_;\n};\n\nRAPIDJSON_NAMESPACE_END\nRAPIDJSON_DIAG_POP\n\n#endif // RAPIDJSON_DOCUMENT_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/encodedstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODEDSTREAM_H_\n#define RAPIDJSON_ENCODEDSTREAM_H_\n\n#include \"stream.h\"\n#include \"memorystream.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Input byte stream wrapper with a statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam InputByteStream Type of input byte stream. For example, FileReadStream.\n*/\ntemplate <typename Encoding, typename InputByteStream>\nclass EncodedInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedInputStream(InputByteStream& is) : is_(is) { \n        current_ = Encoding::TakeBOM(is_);\n    }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }\n    size_t Tell() const { return is_.Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedInputStream(const EncodedInputStream&);\n    EncodedInputStream& operator=(const EncodedInputStream&);\n\n    InputByteStream& is_;\n    Ch current_;\n};\n\n//! Specialized for UTF8 MemoryStream.\ntemplate <>\nclass EncodedInputStream<UTF8<>, MemoryStream> {\npublic:\n    typedef UTF8<>::Ch Ch;\n\n    EncodedInputStream(MemoryStream& is) : is_(is) {\n        if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();\n        if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();\n        if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();\n    }\n    Ch Peek() const { return is_.Peek(); }\n    Ch Take() { return is_.Take(); }\n    size_t Tell() const { return is_.Tell(); }\n\n    // Not implemented\n    void Put(Ch) {}\n    void Flush() {} \n    Ch* PutBegin() { return 0; }\n    size_t PutEnd(Ch*) { return 0; }\n\n    MemoryStream& is_;\n\nprivate:\n    EncodedInputStream(const EncodedInputStream&);\n    EncodedInputStream& operator=(const EncodedInputStream&);\n};\n\n//! Output byte stream wrapper with statically bound encoding.\n/*!\n    \\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.\n    \\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.\n*/\ntemplate <typename Encoding, typename OutputByteStream>\nclass EncodedOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { \n        if (putBOM)\n            Encoding::PutBOM(os_);\n    }\n\n    void Put(Ch c) { Encoding::Put(os_, c);  }\n    void Flush() { os_.Flush(); }\n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}\n    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}\n    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    EncodedOutputStream(const EncodedOutputStream&);\n    EncodedOutputStream& operator=(const EncodedOutputStream&);\n\n    OutputByteStream& os_;\n};\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for reading.\n    \\tparam InputByteStream type of input byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename InputByteStream>\nclass AutoUTFInputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param is input stream to be wrapped.\n        \\param type UTF encoding type if it is not detected from the stream.\n    */\n    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        \n        DetectType();\n        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };\n        takeFunc_ = f[type_];\n        current_ = takeFunc_(*is_);\n    }\n\n    UTFType GetType() const { return type_; }\n    bool HasBOM() const { return hasBOM_; }\n\n    Ch Peek() const { return current_; }\n    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }\n    size_t Tell() const { return is_->Tell(); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFInputStream(const AutoUTFInputStream&);\n    AutoUTFInputStream& operator=(const AutoUTFInputStream&);\n\n    // Detect encoding type with BOM or RFC 4627\n    void DetectType() {\n        // BOM (Byte Order Mark):\n        // 00 00 FE FF  UTF-32BE\n        // FF FE 00 00  UTF-32LE\n        // FE FF        UTF-16BE\n        // FF FE        UTF-16LE\n        // EF BB BF     UTF-8\n\n        const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());\n        if (!c)\n            return;\n\n        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));\n        hasBOM_ = false;\n        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }\n        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }\n        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }\n\n        // RFC 4627: Section 3\n        // \"Since the first two characters of a JSON text will always be ASCII\n        // characters [RFC0020], it is possible to determine whether an octet\n        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking\n        // at the pattern of nulls in the first four octets.\"\n        // 00 00 00 xx  UTF-32BE\n        // 00 xx 00 xx  UTF-16BE\n        // xx 00 00 00  UTF-32LE\n        // xx 00 xx 00  UTF-16LE\n        // xx xx xx xx  UTF-8\n\n        if (!hasBOM_) {\n            unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);\n            switch (pattern) {\n            case 0x08: type_ = kUTF32BE; break;\n            case 0x0A: type_ = kUTF16BE; break;\n            case 0x01: type_ = kUTF32LE; break;\n            case 0x05: type_ = kUTF16LE; break;\n            case 0x0F: type_ = kUTF8;    break;\n            default: break; // Use type defined by user.\n            }\n        }\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n    }\n\n    typedef Ch (*TakeFunc)(InputByteStream& is);\n    InputByteStream* is_;\n    UTFType type_;\n    Ch current_;\n    TakeFunc takeFunc_;\n    bool hasBOM_;\n};\n\n//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.\n/*!\n    \\tparam CharType Type of character for writing.\n    \\tparam OutputByteStream type of output byte stream to be wrapped.\n*/\ntemplate <typename CharType, typename OutputByteStream>\nclass AutoUTFOutputStream {\n    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\npublic:\n    typedef CharType Ch;\n\n    //! Constructor.\n    /*!\n        \\param os output stream to be wrapped.\n        \\param type UTF encoding type.\n        \\param putBOM Whether to write BOM at the beginning of the stream.\n    */\n    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {\n        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);\n\n        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.\n        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);\n        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);\n\n        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };\n        putFunc_ = f[type_];\n\n        if (putBOM)\n            PutBOM();\n    }\n\n    UTFType GetType() const { return type_; }\n\n    void Put(Ch c) { putFunc_(*os_, c); }\n    void Flush() { os_->Flush(); } \n\n    // Not implemented\n    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}\n    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    AutoUTFOutputStream(const AutoUTFOutputStream&);\n    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);\n\n    void PutBOM() { \n        typedef void (*PutBOMFunc)(OutputByteStream&);\n        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };\n        f[type_](*os_);\n    }\n\n    typedef void (*PutFunc)(OutputByteStream&, Ch);\n\n    OutputByteStream* os_;\n    UTFType type_;\n    PutFunc putFunc_;\n};\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/encodings.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ENCODINGS_H_\n#define RAPIDJSON_ENCODINGS_H_\n\n#include \"rapidjson.h\"\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#elif defined(__GNUC__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\nRAPIDJSON_DIAG_OFF(overflow)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Encoding\n\n/*! \\class rapidjson::Encoding\n    \\brief Concept for encoding of Unicode characters.\n\n\\code\nconcept Encoding {\n    typename Ch;    //! Type of character. A \"character\" is actually a code unit in unicode's definition.\n\n    enum { supportUnicode = 1 }; // or 0 if not supporting unicode\n\n    //! \\brief Encode a Unicode codepoint to an output stream.\n    //! \\param os Output stream.\n    //! \\param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint);\n\n    //! \\brief Decode a Unicode codepoint from an input stream.\n    //! \\param is Input stream.\n    //! \\param codepoint Output of the unicode codepoint.\n    //! \\return true if a valid codepoint can be decoded from the stream.\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint);\n\n    //! \\brief Validate one Unicode codepoint from an encoded stream.\n    //! \\param is Input stream to obtain codepoint.\n    //! \\param os Output for copying one codepoint.\n    //! \\return true if it is valid.\n    //! \\note This function just validating and copying the codepoint without actually decode it.\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os);\n\n    // The following functions are deal with byte streams.\n\n    //! Take a character from input byte stream, skip BOM if exist.\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is);\n\n    //! Take a character from input byte stream.\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is);\n\n    //! Put BOM to output byte stream.\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os);\n\n    //! Put a character to output byte stream.\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c);\n};\n\\endcode\n*/\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF8\n\n//! UTF-8 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-8\n    http://tools.ietf.org/html/rfc3629\n    \\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct UTF8 {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        if (codepoint <= 0x7F) \n            os.Put(static_cast<Ch>(codepoint & 0xFF));\n        else if (codepoint <= 0x7FF) {\n            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));\n        }\n        else if (codepoint <= 0xFFFF) {\n            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        if (codepoint <= 0x7F) \n            PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));\n        else if (codepoint <= 0x7FF) {\n            PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));\n        }\n        else if (codepoint <= 0xFFFF) {\n            PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));\n            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)\n#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)\n#define TAIL() COPY(); TRANS(0x70)\n        typename InputStream::Ch c = is.Take();\n        if (!(c & 0x80)) {\n            *codepoint = static_cast<unsigned char>(c);\n            return true;\n        }\n\n        unsigned char type = GetRange(static_cast<unsigned char>(c));\n        if (type >= 32) {\n            *codepoint = 0;\n        } else {\n            *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);\n        }\n        bool result = true;\n        switch (type) {\n        case 2: TAIL(); return result;\n        case 3: TAIL(); TAIL(); return result;\n        case 4: COPY(); TRANS(0x50); TAIL(); return result;\n        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;\n        case 6: TAIL(); TAIL(); TAIL(); return result;\n        case 10: COPY(); TRANS(0x20); TAIL(); return result;\n        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;\n        default: return false;\n        }\n#undef COPY\n#undef TRANS\n#undef TAIL\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n#define COPY() os.Put(c = is.Take())\n#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)\n#define TAIL() COPY(); TRANS(0x70)\n        Ch c;\n        COPY();\n        if (!(c & 0x80))\n            return true;\n\n        bool result = true;\n        switch (GetRange(static_cast<unsigned char>(c))) {\n        case 2: TAIL(); return result;\n        case 3: TAIL(); TAIL(); return result;\n        case 4: COPY(); TRANS(0x50); TAIL(); return result;\n        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;\n        case 6: TAIL(); TAIL(); TAIL(); return result;\n        case 10: COPY(); TRANS(0x20); TAIL(); return result;\n        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;\n        default: return false;\n        }\n#undef COPY\n#undef TRANS\n#undef TAIL\n    }\n\n    static unsigned char GetRange(unsigned char c) {\n        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/\n        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.\n        static const unsigned char type[] = {\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,\n            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,\n            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\n            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,\n            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,\n            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,\n        };\n        return type[c];\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        typename InputByteStream::Ch c = Take(is);\n        if (static_cast<unsigned char>(c) != 0xEFu) return c;\n        c = is.Take();\n        if (static_cast<unsigned char>(c) != 0xBBu) return c;\n        c = is.Take();\n        if (static_cast<unsigned char>(c) != 0xBFu) return c;\n        c = is.Take();\n        return c;\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return static_cast<Ch>(is.Take());\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF16\n\n//! UTF-16 encoding.\n/*! http://en.wikipedia.org/wiki/UTF-16\n    http://tools.ietf.org/html/rfc2781\n    \\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF16LE and UTF16BE, which handle endianness.\n*/\ntemplate<typename CharType = wchar_t>\nstruct UTF16 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        if (codepoint <= 0xFFFF) {\n            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n            os.Put(static_cast<typename OutputStream::Ch>(codepoint));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            unsigned v = codepoint - 0x10000;\n            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));\n            os.Put((v & 0x3FF) | 0xDC00);\n        }\n    }\n\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        if (codepoint <= 0xFFFF) {\n            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair \n            PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));\n        }\n        else {\n            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n            unsigned v = codepoint - 0x10000;\n            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));\n            PutUnsafe(os, (v & 0x3FF) | 0xDC00);\n        }\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        typename InputStream::Ch c = is.Take();\n        if (c < 0xD800 || c > 0xDFFF) {\n            *codepoint = static_cast<unsigned>(c);\n            return true;\n        }\n        else if (c <= 0xDBFF) {\n            *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;\n            c = is.Take();\n            *codepoint |= (static_cast<unsigned>(c) & 0x3FF);\n            *codepoint += 0x10000;\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);\n        typename InputStream::Ch c;\n        os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));\n        if (c < 0xD800 || c > 0xDFFF)\n            return true;\n        else if (c <= 0xDBFF) {\n            os.Put(c = is.Take());\n            return c >= 0xDC00 && c <= 0xDFFF;\n        }\n        return false;\n    }\n};\n\n//! UTF-16 little endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16LE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<uint8_t>(is.Take());\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));\n    }\n};\n\n//! UTF-16 big endian encoding.\ntemplate<typename CharType = wchar_t>\nstruct UTF16BE : UTF16<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<uint8_t>(is.Take());\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// UTF32\n\n//! UTF-32 encoding. \n/*! http://en.wikipedia.org/wiki/UTF-32\n    \\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.\n    \\note implements Encoding concept\n\n    \\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.\n    For streaming, use UTF32LE and UTF32BE, which handle endianness.\n*/\ntemplate<typename CharType = unsigned>\nstruct UTF32 {\n    typedef CharType Ch;\n    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);\n\n    enum { supportUnicode = 1 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);\n        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n        os.Put(codepoint);\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);\n        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);\n        PutUnsafe(os, codepoint);\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c = is.Take();\n        *codepoint = c;\n        return c <= 0x10FFFF;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);\n        Ch c;\n        os.Put(c = is.Take());\n        return c <= 0x10FFFF;\n    }\n};\n\n//! UTF-32 little endian enocoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32LE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;\n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<uint8_t>(is.Take());\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));\n    }\n};\n\n//! UTF-32 big endian encoding.\ntemplate<typename CharType = unsigned>\nstruct UTF32BE : UTF32<CharType> {\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        CharType c = Take(is);\n        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; \n    }\n\n    template <typename InputByteStream>\n    static CharType Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;\n        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));\n        return static_cast<CharType>(c);\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, CharType c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));\n        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// ASCII\n\n//! ASCII encoding.\n/*! http://en.wikipedia.org/wiki/ASCII\n    \\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.\n    \\note implements Encoding concept\n*/\ntemplate<typename CharType = char>\nstruct ASCII {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 0 };\n\n    template<typename OutputStream>\n    static void Encode(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_ASSERT(codepoint <= 0x7F);\n        os.Put(static_cast<Ch>(codepoint & 0xFF));\n    }\n\n    template<typename OutputStream>\n    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        RAPIDJSON_ASSERT(codepoint <= 0x7F);\n        PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));\n    }\n\n    template <typename InputStream>\n    static bool Decode(InputStream& is, unsigned* codepoint) {\n        uint8_t c = static_cast<uint8_t>(is.Take());\n        *codepoint = c;\n        return c <= 0X7F;\n    }\n\n    template <typename InputStream, typename OutputStream>\n    static bool Validate(InputStream& is, OutputStream& os) {\n        uint8_t c = static_cast<uint8_t>(is.Take());\n        os.Put(static_cast<typename OutputStream::Ch>(c));\n        return c <= 0x7F;\n    }\n\n    template <typename InputByteStream>\n    static CharType TakeBOM(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        uint8_t c = static_cast<uint8_t>(Take(is));\n        return static_cast<Ch>(c);\n    }\n\n    template <typename InputByteStream>\n    static Ch Take(InputByteStream& is) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);\n        return static_cast<Ch>(is.Take());\n    }\n\n    template <typename OutputByteStream>\n    static void PutBOM(OutputByteStream& os) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        (void)os;\n    }\n\n    template <typename OutputByteStream>\n    static void Put(OutputByteStream& os, Ch c) {\n        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);\n        os.Put(static_cast<typename OutputByteStream::Ch>(c));\n    }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// AutoUTF\n\n//! Runtime-specified UTF encoding type of a stream.\nenum UTFType {\n    kUTF8 = 0,      //!< UTF-8.\n    kUTF16LE = 1,   //!< UTF-16 little endian.\n    kUTF16BE = 2,   //!< UTF-16 big endian.\n    kUTF32LE = 3,   //!< UTF-32 little endian.\n    kUTF32BE = 4    //!< UTF-32 big endian.\n};\n\n//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.\n/*! \\note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().\n*/\ntemplate<typename CharType>\nstruct AutoUTF {\n    typedef CharType Ch;\n\n    enum { supportUnicode = 1 };\n\n#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x\n\n    template<typename OutputStream>\n    RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {\n        typedef void (*EncodeFunc)(OutputStream&, unsigned);\n        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };\n        (*f[os.GetType()])(os, codepoint);\n    }\n\n    template<typename OutputStream>\n    RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {\n        typedef void (*EncodeFunc)(OutputStream&, unsigned);\n        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };\n        (*f[os.GetType()])(os, codepoint);\n    }\n\n    template <typename InputStream>\n    RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {\n        typedef bool (*DecodeFunc)(InputStream&, unsigned*);\n        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };\n        return (*f[is.GetType()])(is, codepoint);\n    }\n\n    template <typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);\n        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };\n        return (*f[is.GetType()])(is, os);\n    }\n\n#undef RAPIDJSON_ENCODINGS_FUNC\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Transcoder\n\n//! Encoding conversion.\ntemplate<typename SourceEncoding, typename TargetEncoding>\nstruct Transcoder {\n    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {\n        unsigned codepoint;\n        if (!SourceEncoding::Decode(is, &codepoint))\n            return false;\n        TargetEncoding::Encode(os, codepoint);\n        return true;\n    }\n\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {\n        unsigned codepoint;\n        if (!SourceEncoding::Decode(is, &codepoint))\n            return false;\n        TargetEncoding::EncodeUnsafe(os, codepoint);\n        return true;\n    }\n\n    //! Validate one Unicode codepoint from an encoded stream.\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        return Transcode(is, os);   // Since source/target encoding is different, must transcode.\n    }\n};\n\n// Forward declaration.\ntemplate<typename Stream>\ninline void PutUnsafe(Stream& stream, typename Stream::Ch c);\n\n//! Specialization of Transcoder with same source and target encoding.\ntemplate<typename Encoding>\nstruct Transcoder<Encoding, Encoding> {\n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {\n        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.\n        return true;\n    }\n    \n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {\n        PutUnsafe(os, is.Take());  // Just copy one code unit. This semantic is different from primary template class.\n        return true;\n    }\n    \n    template<typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {\n        return Encoding::Validate(is, os);  // source/target encoding are the same\n    }\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__GNUC__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ENCODINGS_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/error/en.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_EN_H_\n#define RAPIDJSON_ERROR_EN_H_\n\n#include \"error.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(covered-switch-default)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Maps error code of parsing into error message.\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\param parseErrorCode Error code obtained in parsing.\n    \\return the error message.\n    \\note User can make a copy of this function for localization.\n        Using switch-case is safer for future modification of error codes.\n*/\ninline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {\n    switch (parseErrorCode) {\n        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING(\"No error.\");\n\n        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING(\"The document is empty.\");\n        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING(\"The document root must not be followed by other values.\");\n    \n        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING(\"Invalid value.\");\n    \n        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING(\"Missing a name for object member.\");\n        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING(\"Missing a colon after a name of object member.\");\n        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or '}' after an object member.\");\n    \n        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING(\"Missing a comma or ']' after an array element.\");\n\n        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING(\"Incorrect hex digit after \\\\u escape in string.\");\n        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING(\"The surrogate pair in string is invalid.\");\n        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING(\"Invalid escape character in string.\");\n        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING(\"Missing a closing quotation mark in string.\");\n        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING(\"Invalid encoding in string.\");\n\n        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING(\"Number too big to be stored in double.\");\n        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING(\"Miss fraction part in number.\");\n        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING(\"Miss exponent in number.\");\n\n        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING(\"Terminate parsing due to Handler error.\");\n        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING(\"Unspecific syntax error.\");\n\n        default:                                        return RAPIDJSON_ERROR_STRING(\"Unknown error.\");\n    }\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ERROR_EN_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/error/error.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ERROR_ERROR_H_\n#define RAPIDJSON_ERROR_ERROR_H_\n\n#include \"../rapidjson.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\n/*! \\file error.h */\n\n/*! \\defgroup RAPIDJSON_ERRORS RapidJSON error handling */\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_CHARTYPE\n\n//! Character type of error messages.\n/*! \\ingroup RAPIDJSON_ERRORS\n    The default character type is \\c char.\n    On Windows, user can define this macro as \\c TCHAR for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_CHARTYPE\n#define RAPIDJSON_ERROR_CHARTYPE char\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ERROR_STRING\n\n//! Macro for converting string literial to \\ref RAPIDJSON_ERROR_CHARTYPE[].\n/*! \\ingroup RAPIDJSON_ERRORS\n    By default this conversion macro does nothing.\n    On Windows, user can define this macro as \\c _T(x) for supporting both\n    unicode/non-unicode settings.\n*/\n#ifndef RAPIDJSON_ERROR_STRING\n#define RAPIDJSON_ERROR_STRING(x) x\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseErrorCode\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericReader::Parse, GenericReader::GetParseErrorCode\n*/\nenum ParseErrorCode {\n    kParseErrorNone = 0,                        //!< No error.\n\n    kParseErrorDocumentEmpty,                   //!< The document is empty.\n    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.\n\n    kParseErrorValueInvalid,                    //!< Invalid value.\n\n    kParseErrorObjectMissName,                  //!< Missing a name for object member.\n    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.\n    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.\n\n    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.\n\n    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\\\u escape in string.\n    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.\n    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.\n    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.\n    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.\n\n    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.\n    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.\n    kParseErrorNumberMissExponent,              //!< Miss exponent in number.\n\n    kParseErrorTermination,                     //!< Parsing was terminated.\n    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.\n};\n\n//! Result of parsing (wraps ParseErrorCode)\n/*!\n    \\ingroup RAPIDJSON_ERRORS\n    \\code\n        Document doc;\n        ParseResult ok = doc.Parse(\"[42]\");\n        if (!ok) {\n            fprintf(stderr, \"JSON parse error: %s (%u)\",\n                    GetParseError_En(ok.Code()), ok.Offset());\n            exit(EXIT_FAILURE);\n        }\n    \\endcode\n    \\see GenericReader::Parse, GenericDocument::Parse\n*/\nstruct ParseResult {\npublic:\n    //! Default constructor, no error.\n    ParseResult() : code_(kParseErrorNone), offset_(0) {}\n    //! Constructor to set an error.\n    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}\n\n    //! Get the error code.\n    ParseErrorCode Code() const { return code_; }\n    //! Get the error offset, if \\ref IsError(), 0 otherwise.\n    size_t Offset() const { return offset_; }\n\n    //! Conversion to \\c bool, returns \\c true, iff !\\ref IsError().\n    operator bool() const { return !IsError(); }\n    //! Whether the result is an error.\n    bool IsError() const { return code_ != kParseErrorNone; }\n\n    bool operator==(const ParseResult& that) const { return code_ == that.code_; }\n    bool operator==(ParseErrorCode code) const { return code_ == code; }\n    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }\n\n    //! Reset error code.\n    void Clear() { Set(kParseErrorNone); }\n    //! Update error code and offset.\n    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }\n\nprivate:\n    ParseErrorCode code_;\n    size_t offset_;\n};\n\n//! Function pointer type of GetParseError().\n/*! \\ingroup RAPIDJSON_ERRORS\n\n    This is the prototype for \\c GetParseError_X(), where \\c X is a locale.\n    User can dynamically change locale in runtime, e.g.:\n\\code\n    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever\n    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());\n\\endcode\n*/\ntypedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_ERROR_ERROR_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/filereadstream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEREADSTREAM_H_\n#define RAPIDJSON_FILEREADSTREAM_H_\n\n#include \"stream.h\"\n#include <cstdio>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(unreachable-code)\nRAPIDJSON_DIAG_OFF(missing-noreturn)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! File byte stream for input using fread().\n/*!\n    \\note implements Stream concept\n*/\nclass FileReadStream {\npublic:\n    typedef char Ch;    //!< Character type (byte).\n\n    //! Constructor.\n    /*!\n        \\param fp File pointer opened for read.\n        \\param buffer user-supplied buffer.\n        \\param bufferSize size of buffer in bytes. Must >=4 bytes.\n    */\n    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n        RAPIDJSON_ASSERT(bufferSize >= 4);\n        Read();\n    }\n\n    Ch Peek() const { return *current_; }\n    Ch Take() { Ch c = *current_; Read(); return c; }\n    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }\n\n    // Not implemented\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); } \n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return (current_ + 4 <= bufferLast_) ? current_ : 0;\n    }\n\nprivate:\n    void Read() {\n        if (current_ < bufferLast_)\n            ++current_;\n        else if (!eof_) {\n            count_ += readCount_;\n            readCount_ = fread(buffer_, 1, bufferSize_, fp_);\n            bufferLast_ = buffer_ + readCount_ - 1;\n            current_ = buffer_;\n\n            if (readCount_ < bufferSize_) {\n                buffer_[readCount_] = '\\0';\n                ++bufferLast_;\n                eof_ = true;\n            }\n        }\n    }\n\n    std::FILE* fp_;\n    Ch *buffer_;\n    size_t bufferSize_;\n    Ch *bufferLast_;\n    Ch *current_;\n    size_t readCount_;\n    size_t count_;  //!< Number of characters read\n    bool eof_;\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/filewritestream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FILEWRITESTREAM_H_\n#define RAPIDJSON_FILEWRITESTREAM_H_\n\n#include \"stream.h\"\n#include <cstdio>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(unreachable-code)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of C file stream for input using fread().\n/*!\n    \\note implements Stream concept\n*/\nclass FileWriteStream {\npublic:\n    typedef char Ch;    //!< Character type. Only support char.\n\n    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { \n        RAPIDJSON_ASSERT(fp_ != 0);\n    }\n\n    void Put(char c) { \n        if (current_ >= bufferEnd_)\n            Flush();\n\n        *current_++ = c;\n    }\n\n    void PutN(char c, size_t n) {\n        size_t avail = static_cast<size_t>(bufferEnd_ - current_);\n        while (n > avail) {\n            std::memset(current_, c, avail);\n            current_ += avail;\n            Flush();\n            n -= avail;\n            avail = static_cast<size_t>(bufferEnd_ - current_);\n        }\n\n        if (n > 0) {\n            std::memset(current_, c, n);\n            current_ += n;\n        }\n    }\n\n    void Flush() {\n        if (current_ != buffer_) {\n            size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);\n            if (result < static_cast<size_t>(current_ - buffer_)) {\n                // failure deliberately ignored at this time\n                // added to avoid warn_unused_result build errors\n            }\n            current_ = buffer_;\n        }\n    }\n\n    // Not implemented\n    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }\n    char Take() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    FileWriteStream(const FileWriteStream&);\n    FileWriteStream& operator=(const FileWriteStream&);\n\n    std::FILE* fp_;\n    char *buffer_;\n    char *bufferEnd_;\n    char *current_;\n};\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(FileWriteStream& stream, char c, size_t n) {\n    stream.PutN(c, n);\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_FILESTREAM_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/fwd.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_FWD_H_\n#define RAPIDJSON_FWD_H_\n\n#include \"rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n// encodings.h\n\ntemplate<typename CharType> struct UTF8;\ntemplate<typename CharType> struct UTF16;\ntemplate<typename CharType> struct UTF16BE;\ntemplate<typename CharType> struct UTF16LE;\ntemplate<typename CharType> struct UTF32;\ntemplate<typename CharType> struct UTF32BE;\ntemplate<typename CharType> struct UTF32LE;\ntemplate<typename CharType> struct ASCII;\ntemplate<typename CharType> struct AutoUTF;\n\ntemplate<typename SourceEncoding, typename TargetEncoding>\nstruct Transcoder;\n\n// allocators.h\n\nclass CrtAllocator;\n\ntemplate <typename BaseAllocator>\nclass MemoryPoolAllocator;\n\n// stream.h\n\ntemplate <typename Encoding>\nstruct GenericStringStream;\n\ntypedef GenericStringStream<UTF8<char> > StringStream;\n\ntemplate <typename Encoding>\nstruct GenericInsituStringStream;\n\ntypedef GenericInsituStringStream<UTF8<char> > InsituStringStream;\n\n// stringbuffer.h\n\ntemplate <typename Encoding, typename Allocator>\nclass GenericStringBuffer;\n\ntypedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;\n\n// filereadstream.h\n\nclass FileReadStream;\n\n// filewritestream.h\n\nclass FileWriteStream;\n\n// memorybuffer.h\n\ntemplate <typename Allocator>\nstruct GenericMemoryBuffer;\n\ntypedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;\n\n// memorystream.h\n\nstruct MemoryStream;\n\n// reader.h\n\ntemplate<typename Encoding, typename Derived>\nstruct BaseReaderHandler;\n\ntemplate <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>\nclass GenericReader;\n\ntypedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;\n\n// writer.h\n\ntemplate<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>\nclass Writer;\n\n// prettywriter.h\n\ntemplate<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>\nclass PrettyWriter;\n\n// document.h\n\ntemplate <typename Encoding, typename Allocator> \nstruct GenericMember;\n\ntemplate <bool Const, typename Encoding, typename Allocator>\nclass GenericMemberIterator;\n\ntemplate<typename CharType>\nstruct GenericStringRef;\n\ntemplate <typename Encoding, typename Allocator> \nclass GenericValue;\n\ntypedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;\n\ntemplate <typename Encoding, typename Allocator, typename StackAllocator>\nclass GenericDocument;\n\ntypedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;\n\n// pointer.h\n\ntemplate <typename ValueType, typename Allocator>\nclass GenericPointer;\n\ntypedef GenericPointer<Value, CrtAllocator> Pointer;\n\n// schema.h\n\ntemplate <typename SchemaDocumentType>\nclass IGenericRemoteSchemaDocumentProvider;\n\ntemplate <typename ValueT, typename Allocator>\nclass GenericSchemaDocument;\n\ntypedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;\ntypedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;\n\ntemplate <\n    typename SchemaDocumentType,\n    typename OutputHandler,\n    typename StateAllocator>\nclass GenericSchemaValidator;\n\ntypedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_RAPIDJSONFWD_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/biginteger.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_BIGINTEGER_H_\n#define RAPIDJSON_BIGINTEGER_H_\n\n#include \"../rapidjson.h\"\n\n#if defined(_MSC_VER) && defined(_M_AMD64)\n#include <intrin.h> // for _umul128\n#pragma intrinsic(_umul128)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass BigInteger {\npublic:\n    typedef uint64_t Type;\n\n    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {\n        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));\n    }\n\n    explicit BigInteger(uint64_t u) : count_(1) {\n        digits_[0] = u;\n    }\n\n    BigInteger(const char* decimals, size_t length) : count_(1) {\n        RAPIDJSON_ASSERT(length > 0);\n        digits_[0] = 0;\n        size_t i = 0;\n        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19\n        while (length >= kMaxDigitPerIteration) {\n            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);\n            length -= kMaxDigitPerIteration;\n            i += kMaxDigitPerIteration;\n        }\n\n        if (length > 0)\n            AppendDecimal64(decimals + i, decimals + i + length);\n    }\n    \n    BigInteger& operator=(const BigInteger &rhs)\n    {\n        if (this != &rhs) {\n            count_ = rhs.count_;\n            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));\n        }\n        return *this;\n    }\n    \n    BigInteger& operator=(uint64_t u) {\n        digits_[0] = u;            \n        count_ = 1;\n        return *this;\n    }\n\n    BigInteger& operator+=(uint64_t u) {\n        Type backup = digits_[0];\n        digits_[0] += u;\n        for (size_t i = 0; i < count_ - 1; i++) {\n            if (digits_[i] >= backup)\n                return *this; // no carry\n            backup = digits_[i + 1];\n            digits_[i + 1] += 1;\n        }\n\n        // Last carry\n        if (digits_[count_ - 1] < backup)\n            PushBack(1);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint64_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            uint64_t hi;\n            digits_[i] = MulAdd64(digits_[i], u, k, &hi);\n            k = hi;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator*=(uint32_t u) {\n        if (u == 0) return *this = 0;\n        if (u == 1) return *this;\n        if (*this == 1) return *this = u;\n\n        uint64_t k = 0;\n        for (size_t i = 0; i < count_; i++) {\n            const uint64_t c = digits_[i] >> 32;\n            const uint64_t d = digits_[i] & 0xFFFFFFFF;\n            const uint64_t uc = u * c;\n            const uint64_t ud = u * d;\n            const uint64_t p0 = ud + k;\n            const uint64_t p1 = uc + (p0 >> 32);\n            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);\n            k = p1 >> 32;\n        }\n        \n        if (k > 0)\n            PushBack(k);\n\n        return *this;\n    }\n\n    BigInteger& operator<<=(size_t shift) {\n        if (IsZero() || shift == 0) return *this;\n\n        size_t offset = shift / kTypeBit;\n        size_t interShift = shift % kTypeBit;\n        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);\n\n        if (interShift == 0) {\n            std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));\n            count_ += offset;\n        }\n        else {\n            digits_[count_] = 0;\n            for (size_t i = count_; i > 0; i--)\n                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));\n            digits_[offset] = digits_[0] << interShift;\n            count_ += offset;\n            if (digits_[count_])\n                count_++;\n        }\n\n        std::memset(digits_, 0, offset * sizeof(Type));\n\n        return *this;\n    }\n\n    bool operator==(const BigInteger& rhs) const {\n        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;\n    }\n\n    bool operator==(const Type rhs) const {\n        return count_ == 1 && digits_[0] == rhs;\n    }\n\n    BigInteger& MultiplyPow5(unsigned exp) {\n        static const uint32_t kPow5[12] = {\n            5,\n            5 * 5,\n            5 * 5 * 5,\n            5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,\n            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5\n        };\n        if (exp == 0) return *this;\n        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27\n        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13\n        if (exp > 0)                 *this *= kPow5[exp - 1];\n        return *this;\n    }\n\n    // Compute absolute difference of this and rhs.\n    // Assume this != rhs\n    bool Difference(const BigInteger& rhs, BigInteger* out) const {\n        int cmp = Compare(rhs);\n        RAPIDJSON_ASSERT(cmp != 0);\n        const BigInteger *a, *b;  // Makes a > b\n        bool ret;\n        if (cmp < 0) { a = &rhs; b = this; ret = true; }\n        else         { a = this; b = &rhs; ret = false; }\n\n        Type borrow = 0;\n        for (size_t i = 0; i < a->count_; i++) {\n            Type d = a->digits_[i] - borrow;\n            if (i < b->count_)\n                d -= b->digits_[i];\n            borrow = (d > a->digits_[i]) ? 1 : 0;\n            out->digits_[i] = d;\n            if (d != 0)\n                out->count_ = i + 1;\n        }\n\n        return ret;\n    }\n\n    int Compare(const BigInteger& rhs) const {\n        if (count_ != rhs.count_)\n            return count_ < rhs.count_ ? -1 : 1;\n\n        for (size_t i = count_; i-- > 0;)\n            if (digits_[i] != rhs.digits_[i])\n                return digits_[i] < rhs.digits_[i] ? -1 : 1;\n\n        return 0;\n    }\n\n    size_t GetCount() const { return count_; }\n    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }\n    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }\n\nprivate:\n    void AppendDecimal64(const char* begin, const char* end) {\n        uint64_t u = ParseUint64(begin, end);\n        if (IsZero())\n            *this = u;\n        else {\n            unsigned exp = static_cast<unsigned>(end - begin);\n            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u\n        }\n    }\n\n    void PushBack(Type digit) {\n        RAPIDJSON_ASSERT(count_ < kCapacity);\n        digits_[count_++] = digit;\n    }\n\n    static uint64_t ParseUint64(const char* begin, const char* end) {\n        uint64_t r = 0;\n        for (const char* p = begin; p != end; ++p) {\n            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');\n            r = r * 10u + static_cast<unsigned>(*p - '0');\n        }\n        return r;\n    }\n\n    // Assume a * b + k < 2^128\n    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t low = _umul128(a, b, outHigh) + k;\n        if (low < k)\n            (*outHigh)++;\n        return low;\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);\n        p += k;\n        *outHigh = static_cast<uint64_t>(p >> 64);\n        return static_cast<uint64_t>(p);\n#else\n        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;\n        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;\n        x1 += (x0 >> 32); // can't give carry\n        x1 += x2;\n        if (x1 < x2)\n            x3 += (static_cast<uint64_t>(1) << 32);\n        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);\n        uint64_t hi = x3 + (x1 >> 32);\n\n        lo += k;\n        if (lo < k)\n            hi++;\n        *outHigh = hi;\n        return lo;\n#endif\n    }\n\n    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000\n    static const size_t kCapacity = kBitCount / sizeof(Type);\n    static const size_t kTypeBit = sizeof(Type) * 8;\n\n    Type digits_[kCapacity];\n    size_t count_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_BIGINTEGER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/diyfp.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DIYFP_H_\n#define RAPIDJSON_DIYFP_H_\n\n#include \"../rapidjson.h\"\n\n#if defined(_MSC_VER) && defined(_M_AMD64)\n#include <intrin.h>\n#pragma intrinsic(_BitScanReverse64)\n#pragma intrinsic(_umul128)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nstruct DiyFp {\n    DiyFp() : f(), e() {}\n\n    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}\n\n    explicit DiyFp(double d) {\n        union {\n            double d;\n            uint64_t u64;\n        } u = { d };\n\n        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);\n        uint64_t significand = (u.u64 & kDpSignificandMask);\n        if (biased_e != 0) {\n            f = significand + kDpHiddenBit;\n            e = biased_e - kDpExponentBias;\n        } \n        else {\n            f = significand;\n            e = kDpMinExponent + 1;\n        }\n    }\n\n    DiyFp operator-(const DiyFp& rhs) const {\n        return DiyFp(f - rhs.f, e);\n    }\n\n    DiyFp operator*(const DiyFp& rhs) const {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        uint64_t h;\n        uint64_t l = _umul128(f, rhs.f, &h);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)\n        __extension__ typedef unsigned __int128 uint128;\n        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);\n        uint64_t h = static_cast<uint64_t>(p >> 64);\n        uint64_t l = static_cast<uint64_t>(p);\n        if (l & (uint64_t(1) << 63)) // rounding\n            h++;\n        return DiyFp(h, e + rhs.e + 64);\n#else\n        const uint64_t M32 = 0xFFFFFFFF;\n        const uint64_t a = f >> 32;\n        const uint64_t b = f & M32;\n        const uint64_t c = rhs.f >> 32;\n        const uint64_t d = rhs.f & M32;\n        const uint64_t ac = a * c;\n        const uint64_t bc = b * c;\n        const uint64_t ad = a * d;\n        const uint64_t bd = b * d;\n        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);\n        tmp += 1U << 31;  /// mult_round\n        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);\n#endif\n    }\n\n    DiyFp Normalize() const {\n#if defined(_MSC_VER) && defined(_M_AMD64)\n        unsigned long index;\n        _BitScanReverse64(&index, f);\n        return DiyFp(f << (63 - index), e - (63 - index));\n#elif defined(__GNUC__) && __GNUC__ >= 4\n        int s = __builtin_clzll(f);\n        return DiyFp(f << s, e - s);\n#else\n        DiyFp res = *this;\n        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        return res;\n#endif\n    }\n\n    DiyFp NormalizeBoundary() const {\n        DiyFp res = *this;\n        while (!(res.f & (kDpHiddenBit << 1))) {\n            res.f <<= 1;\n            res.e--;\n        }\n        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);\n        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);\n        return res;\n    }\n\n    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {\n        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();\n        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);\n        mi.f <<= mi.e - pl.e;\n        mi.e = pl.e;\n        *plus = pl;\n        *minus = mi;\n    }\n\n    double ToDouble() const {\n        union {\n            double d;\n            uint64_t u64;\n        }u;\n        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : \n            static_cast<uint64_t>(e + kDpExponentBias);\n        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);\n        return u.d;\n    }\n\n    static const int kDiySignificandSize = 64;\n    static const int kDpSignificandSize = 52;\n    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;\n    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;\n    static const int kDpMinExponent = -kDpExponentBias;\n    static const int kDpDenormalExponent = -kDpExponentBias + 1;\n    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    uint64_t f;\n    int e;\n};\n\ninline DiyFp GetCachedPowerByIndex(size_t index) {\n    // 10^-348, 10^-340, ..., 10^340\n    static const uint64_t kCachedPowers_F[] = {\n        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),\n        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),\n        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),\n        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),\n        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),\n        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),\n        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),\n        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),\n        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),\n        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),\n        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),\n        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),\n        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),\n        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),\n        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),\n        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),\n        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),\n        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),\n        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),\n        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),\n        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),\n        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),\n        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),\n        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),\n        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),\n        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),\n        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),\n        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),\n        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),\n        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),\n        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),\n        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),\n        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),\n        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),\n        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),\n        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),\n        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),\n        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),\n        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),\n        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),\n        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),\n        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),\n        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),\n        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)\n    };\n    static const int16_t kCachedPowers_E[] = {\n        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,\n        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,\n        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,\n        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,\n        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,\n        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,\n        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,\n        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,\n        907,   933,   960,   986,  1013,  1039,  1066\n    };\n    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);\n}\n    \ninline DiyFp GetCachedPower(int e, int* K) {\n\n    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;\n    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive\n    int k = static_cast<int>(dk);\n    if (dk - k > 0.0)\n        k++;\n\n    unsigned index = static_cast<unsigned>((k >> 3) + 1);\n    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table\n\n    return GetCachedPowerByIndex(index);\n}\n\ninline DiyFp GetCachedPower10(int exp, int *outExp) {\n     unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;\n     *outExp = -348 + static_cast<int>(index) * 8;\n     return GetCachedPowerByIndex(index);\n }\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DIYFP_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/dtoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n// This is a C++ header-only implementation of Grisu2 algorithm from the publication:\n// Loitsch, Florian. \"Printing floating-point numbers quickly and accurately with\n// integers.\" ACM Sigplan Notices 45.6 (2010): 233-243.\n\n#ifndef RAPIDJSON_DTOA_\n#define RAPIDJSON_DTOA_\n\n#include \"itoa.h\" // GetDigitsLut()\n#include \"diyfp.h\"\n#include \"ieee754.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\nRAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124\n#endif\n\ninline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {\n    while (rest < wp_w && delta - rest >= ten_kappa &&\n           (rest + ten_kappa < wp_w ||  /// closer\n            wp_w - rest > rest + ten_kappa - wp_w)) {\n        buffer[len - 1]--;\n        rest += ten_kappa;\n    }\n}\n\ninline unsigned CountDecimalDigit32(uint32_t n) {\n    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.\n    if (n < 10) return 1;\n    if (n < 100) return 2;\n    if (n < 1000) return 3;\n    if (n < 10000) return 4;\n    if (n < 100000) return 5;\n    if (n < 1000000) return 6;\n    if (n < 10000000) return 7;\n    if (n < 100000000) return 8;\n    // Will not reach 10 digits in DigitGen()\n    //if (n < 1000000000) return 9;\n    //return 10;\n    return 9;\n}\n\ninline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {\n    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };\n    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);\n    const DiyFp wp_w = Mp - W;\n    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);\n    uint64_t p2 = Mp.f & (one.f - 1);\n    unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]\n    *len = 0;\n\n    while (kappa > 0) {\n        uint32_t d = 0;\n        switch (kappa) {\n            case  9: d = p1 /  100000000; p1 %=  100000000; break;\n            case  8: d = p1 /   10000000; p1 %=   10000000; break;\n            case  7: d = p1 /    1000000; p1 %=    1000000; break;\n            case  6: d = p1 /     100000; p1 %=     100000; break;\n            case  5: d = p1 /      10000; p1 %=      10000; break;\n            case  4: d = p1 /       1000; p1 %=       1000; break;\n            case  3: d = p1 /        100; p1 %=        100; break;\n            case  2: d = p1 /         10; p1 %=         10; break;\n            case  1: d = p1;              p1 =           0; break;\n            default:;\n        }\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));\n        kappa--;\n        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;\n        if (tmp <= delta) {\n            *K += kappa;\n            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);\n            return;\n        }\n    }\n\n    // kappa = 0\n    for (;;) {\n        p2 *= 10;\n        delta *= 10;\n        char d = static_cast<char>(p2 >> -one.e);\n        if (d || *len)\n            buffer[(*len)++] = static_cast<char>('0' + d);\n        p2 &= one.f - 1;\n        kappa--;\n        if (p2 < delta) {\n            *K += kappa;\n            int index = -static_cast<int>(kappa);\n            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));\n            return;\n        }\n    }\n}\n\ninline void Grisu2(double value, char* buffer, int* length, int* K) {\n    const DiyFp v(value);\n    DiyFp w_m, w_p;\n    v.NormalizedBoundaries(&w_m, &w_p);\n\n    const DiyFp c_mk = GetCachedPower(w_p.e, K);\n    const DiyFp W = v.Normalize() * c_mk;\n    DiyFp Wp = w_p * c_mk;\n    DiyFp Wm = w_m * c_mk;\n    Wm.f++;\n    Wp.f--;\n    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);\n}\n\ninline char* WriteExponent(int K, char* buffer) {\n    if (K < 0) {\n        *buffer++ = '-';\n        K = -K;\n    }\n\n    if (K >= 100) {\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));\n        K %= 100;\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else if (K >= 10) {\n        const char* d = GetDigitsLut() + K * 2;\n        *buffer++ = d[0];\n        *buffer++ = d[1];\n    }\n    else\n        *buffer++ = static_cast<char>('0' + static_cast<char>(K));\n\n    return buffer;\n}\n\ninline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {\n    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk\n\n    if (0 <= k && kk <= 21) {\n        // 1234e7 -> 12340000000\n        for (int i = length; i < kk; i++)\n            buffer[i] = '0';\n        buffer[kk] = '.';\n        buffer[kk + 1] = '0';\n        return &buffer[kk + 2];\n    }\n    else if (0 < kk && kk <= 21) {\n        // 1234e-2 -> 12.34\n        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));\n        buffer[kk] = '.';\n        if (0 > k + maxDecimalPlaces) {\n            // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1\n            // Remove extra trailing zeros (at least one) after truncation.\n            for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)\n                if (buffer[i] != '0')\n                    return &buffer[i + 1];\n            return &buffer[kk + 2]; // Reserve one zero\n        }\n        else\n            return &buffer[length + 1];\n    }\n    else if (-6 < kk && kk <= 0) {\n        // 1234e-6 -> 0.001234\n        const int offset = 2 - kk;\n        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));\n        buffer[0] = '0';\n        buffer[1] = '.';\n        for (int i = 2; i < offset; i++)\n            buffer[i] = '0';\n        if (length - kk > maxDecimalPlaces) {\n            // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1\n            // Remove extra trailing zeros (at least one) after truncation.\n            for (int i = maxDecimalPlaces + 1; i > 2; i--)\n                if (buffer[i] != '0')\n                    return &buffer[i + 1];\n            return &buffer[3]; // Reserve one zero\n        }\n        else\n            return &buffer[length + offset];\n    }\n    else if (kk < -maxDecimalPlaces) {\n        // Truncate to zero\n        buffer[0] = '0';\n        buffer[1] = '.';\n        buffer[2] = '0';\n        return &buffer[3];\n    }\n    else if (length == 1) {\n        // 1e30\n        buffer[1] = 'e';\n        return WriteExponent(kk - 1, &buffer[2]);\n    }\n    else {\n        // 1234e30 -> 1.234e33\n        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));\n        buffer[1] = '.';\n        buffer[length + 1] = 'e';\n        return WriteExponent(kk - 1, &buffer[0 + length + 2]);\n    }\n}\n\ninline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {\n    RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);\n    Double d(value);\n    if (d.IsZero()) {\n        if (d.Sign())\n            *buffer++ = '-';     // -0.0, Issue #289\n        buffer[0] = '0';\n        buffer[1] = '.';\n        buffer[2] = '0';\n        return &buffer[3];\n    }\n    else {\n        if (value < 0) {\n            *buffer++ = '-';\n            value = -value;\n        }\n        int length, K;\n        Grisu2(value, buffer, &length, &K);\n        return Prettify(buffer, length, K, maxDecimalPlaces);\n    }\n}\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_DTOA_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/ieee754.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_IEEE754_\n#define RAPIDJSON_IEEE754_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\nclass Double {\npublic:\n    Double() {}\n    Double(double d) : d_(d) {}\n    Double(uint64_t u) : u_(u) {}\n\n    double Value() const { return d_; }\n    uint64_t Uint64Value() const { return u_; }\n\n    double NextPositiveDouble() const {\n        RAPIDJSON_ASSERT(!Sign());\n        return Double(u_ + 1).Value();\n    }\n\n    bool Sign() const { return (u_ & kSignMask) != 0; }\n    uint64_t Significand() const { return u_ & kSignificandMask; }\n    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }\n\n    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }\n    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }\n    bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }\n    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }\n    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }\n\n    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }\n    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }\n    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }\n\n    static unsigned EffectiveSignificandSize(int order) {\n        if (order >= -1021)\n            return 53;\n        else if (order <= -1074)\n            return 0;\n        else\n            return static_cast<unsigned>(order) + 1074;\n    }\n\nprivate:\n    static const int kSignificandSize = 52;\n    static const int kExponentBias = 0x3FF;\n    static const int kDenormalExponent = 1 - kExponentBias;\n    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);\n    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);\n    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);\n    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);\n\n    union {\n        double d_;\n        uint64_t u_;\n    };\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_IEEE754_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/itoa.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ITOA_\n#define RAPIDJSON_ITOA_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline const char* GetDigitsLut() {\n    static const char cDigitsLut[200] = {\n        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',\n        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',\n        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',\n        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',\n        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',\n        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',\n        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',\n        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',\n        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',\n        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'\n    };\n    return cDigitsLut;\n}\n\ninline char* u32toa(uint32_t value, char* buffer) {\n    const char* cDigitsLut = GetDigitsLut();\n\n    if (value < 10000) {\n        const uint32_t d1 = (value / 100) << 1;\n        const uint32_t d2 = (value % 100) << 1;\n        \n        if (value >= 1000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 100)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 10)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n    }\n    else if (value < 100000000) {\n        // value = bbbbcccc\n        const uint32_t b = value / 10000;\n        const uint32_t c = value % 10000;\n        \n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n        \n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n        \n        if (value >= 10000000)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= 1000000)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= 100000)\n            *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        \n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    else {\n        // value = aabbbbcccc in decimal\n        \n        const uint32_t a = value / 100000000; // 1 to 42\n        value %= 100000000;\n        \n        if (a >= 10) {\n            const unsigned i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n\n        const uint32_t b = value / 10000; // 0 to 9999\n        const uint32_t c = value % 10000; // 0 to 9999\n        \n        const uint32_t d1 = (b / 100) << 1;\n        const uint32_t d2 = (b % 100) << 1;\n        \n        const uint32_t d3 = (c / 100) << 1;\n        const uint32_t d4 = (c % 100) << 1;\n        \n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n    }\n    return buffer;\n}\n\ninline char* i32toa(int32_t value, char* buffer) {\n    uint32_t u = static_cast<uint32_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u32toa(u, buffer);\n}\n\ninline char* u64toa(uint64_t value, char* buffer) {\n    const char* cDigitsLut = GetDigitsLut();\n    const uint64_t  kTen8 = 100000000;\n    const uint64_t  kTen9 = kTen8 * 10;\n    const uint64_t kTen10 = kTen8 * 100;\n    const uint64_t kTen11 = kTen8 * 1000;\n    const uint64_t kTen12 = kTen8 * 10000;\n    const uint64_t kTen13 = kTen8 * 100000;\n    const uint64_t kTen14 = kTen8 * 1000000;\n    const uint64_t kTen15 = kTen8 * 10000000;\n    const uint64_t kTen16 = kTen8 * kTen8;\n    \n    if (value < kTen8) {\n        uint32_t v = static_cast<uint32_t>(value);\n        if (v < 10000) {\n            const uint32_t d1 = (v / 100) << 1;\n            const uint32_t d2 = (v % 100) << 1;\n            \n            if (v >= 1000)\n                *buffer++ = cDigitsLut[d1];\n            if (v >= 100)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (v >= 10)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n        }\n        else {\n            // value = bbbbcccc\n            const uint32_t b = v / 10000;\n            const uint32_t c = v % 10000;\n            \n            const uint32_t d1 = (b / 100) << 1;\n            const uint32_t d2 = (b % 100) << 1;\n            \n            const uint32_t d3 = (c / 100) << 1;\n            const uint32_t d4 = (c % 100) << 1;\n            \n            if (value >= 10000000)\n                *buffer++ = cDigitsLut[d1];\n            if (value >= 1000000)\n                *buffer++ = cDigitsLut[d1 + 1];\n            if (value >= 100000)\n                *buffer++ = cDigitsLut[d2];\n            *buffer++ = cDigitsLut[d2 + 1];\n            \n            *buffer++ = cDigitsLut[d3];\n            *buffer++ = cDigitsLut[d3 + 1];\n            *buffer++ = cDigitsLut[d4];\n            *buffer++ = cDigitsLut[d4 + 1];\n        }\n    }\n    else if (value < kTen16) {\n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n        \n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n        \n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n        \n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n\n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n        \n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n        \n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n\n        if (value >= kTen15)\n            *buffer++ = cDigitsLut[d1];\n        if (value >= kTen14)\n            *buffer++ = cDigitsLut[d1 + 1];\n        if (value >= kTen13)\n            *buffer++ = cDigitsLut[d2];\n        if (value >= kTen12)\n            *buffer++ = cDigitsLut[d2 + 1];\n        if (value >= kTen11)\n            *buffer++ = cDigitsLut[d3];\n        if (value >= kTen10)\n            *buffer++ = cDigitsLut[d3 + 1];\n        if (value >= kTen9)\n            *buffer++ = cDigitsLut[d4];\n        if (value >= kTen8)\n            *buffer++ = cDigitsLut[d4 + 1];\n        \n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n    else {\n        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844\n        value %= kTen16;\n        \n        if (a < 10)\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a));\n        else if (a < 100) {\n            const uint32_t i = a << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else if (a < 1000) {\n            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));\n            \n            const uint32_t i = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n        }\n        else {\n            const uint32_t i = (a / 100) << 1;\n            const uint32_t j = (a % 100) << 1;\n            *buffer++ = cDigitsLut[i];\n            *buffer++ = cDigitsLut[i + 1];\n            *buffer++ = cDigitsLut[j];\n            *buffer++ = cDigitsLut[j + 1];\n        }\n        \n        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);\n        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);\n        \n        const uint32_t b0 = v0 / 10000;\n        const uint32_t c0 = v0 % 10000;\n        \n        const uint32_t d1 = (b0 / 100) << 1;\n        const uint32_t d2 = (b0 % 100) << 1;\n        \n        const uint32_t d3 = (c0 / 100) << 1;\n        const uint32_t d4 = (c0 % 100) << 1;\n        \n        const uint32_t b1 = v1 / 10000;\n        const uint32_t c1 = v1 % 10000;\n        \n        const uint32_t d5 = (b1 / 100) << 1;\n        const uint32_t d6 = (b1 % 100) << 1;\n        \n        const uint32_t d7 = (c1 / 100) << 1;\n        const uint32_t d8 = (c1 % 100) << 1;\n        \n        *buffer++ = cDigitsLut[d1];\n        *buffer++ = cDigitsLut[d1 + 1];\n        *buffer++ = cDigitsLut[d2];\n        *buffer++ = cDigitsLut[d2 + 1];\n        *buffer++ = cDigitsLut[d3];\n        *buffer++ = cDigitsLut[d3 + 1];\n        *buffer++ = cDigitsLut[d4];\n        *buffer++ = cDigitsLut[d4 + 1];\n        *buffer++ = cDigitsLut[d5];\n        *buffer++ = cDigitsLut[d5 + 1];\n        *buffer++ = cDigitsLut[d6];\n        *buffer++ = cDigitsLut[d6 + 1];\n        *buffer++ = cDigitsLut[d7];\n        *buffer++ = cDigitsLut[d7 + 1];\n        *buffer++ = cDigitsLut[d8];\n        *buffer++ = cDigitsLut[d8 + 1];\n    }\n    \n    return buffer;\n}\n\ninline char* i64toa(int64_t value, char* buffer) {\n    uint64_t u = static_cast<uint64_t>(value);\n    if (value < 0) {\n        *buffer++ = '-';\n        u = ~u + 1;\n    }\n\n    return u64toa(u, buffer);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ITOA_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/meta.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_META_H_\n#define RAPIDJSON_INTERNAL_META_H_\n\n#include \"../rapidjson.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n#if defined(_MSC_VER)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(6334)\n#endif\n\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n#include <type_traits>\n#endif\n\n//@cond RAPIDJSON_INTERNAL\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching\ntemplate <typename T> struct Void { typedef void Type; };\n\n///////////////////////////////////////////////////////////////////////////////\n// BoolType, TrueType, FalseType\n//\ntemplate <bool Cond> struct BoolType {\n    static const bool Value = Cond;\n    typedef BoolType Type;\n};\ntypedef BoolType<true> TrueType;\ntypedef BoolType<false> FalseType;\n\n\n///////////////////////////////////////////////////////////////////////////////\n// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr\n//\n\ntemplate <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };\ntemplate <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };\ntemplate <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};\ntemplate <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};\n\ntemplate <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};\ntemplate <> struct AndExprCond<true, true> : TrueType {};\ntemplate <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};\ntemplate <> struct OrExprCond<false, false> : FalseType {};\n\ntemplate <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};\ntemplate <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};\ntemplate <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};\ntemplate <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};\n\n\n///////////////////////////////////////////////////////////////////////////////\n// AddConst, MaybeAddConst, RemoveConst\ntemplate <typename T> struct AddConst { typedef const T Type; };\ntemplate <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};\ntemplate <typename T> struct RemoveConst { typedef T Type; };\ntemplate <typename T> struct RemoveConst<const T> { typedef T Type; };\n\n\n///////////////////////////////////////////////////////////////////////////////\n// IsSame, IsConst, IsMoreConst, IsPointer\n//\ntemplate <typename T, typename U> struct IsSame : FalseType {};\ntemplate <typename T> struct IsSame<T, T> : TrueType {};\n\ntemplate <typename T> struct IsConst : FalseType {};\ntemplate <typename T> struct IsConst<const T> : TrueType {};\n\ntemplate <typename CT, typename T>\nstruct IsMoreConst\n    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,\n              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};\n\ntemplate <typename T> struct IsPointer : FalseType {};\ntemplate <typename T> struct IsPointer<T*> : TrueType {};\n\n///////////////////////////////////////////////////////////////////////////////\n// IsBaseOf\n//\n#if RAPIDJSON_HAS_CXX11_TYPETRAITS\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : BoolType< ::std::is_base_of<B,D>::value> {};\n\n#else // simplified version adopted from Boost\n\ntemplate<typename B, typename D> struct IsBaseOfImpl {\n    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);\n    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);\n\n    typedef char (&Yes)[1];\n    typedef char (&No) [2];\n\n    template <typename T>\n    static Yes Check(const D*, T);\n    static No  Check(const B*, int);\n\n    struct Host {\n        operator const B*() const;\n        operator const D*();\n    };\n\n    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };\n};\n\ntemplate <typename B, typename D> struct IsBaseOf\n    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};\n\n#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS\n\n\n//////////////////////////////////////////////////////////////////////////\n// EnableIf / DisableIf\n//\ntemplate <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };\ntemplate <typename T> struct EnableIfCond<false, T> { /* empty */ };\n\ntemplate <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };\ntemplate <typename T> struct DisableIfCond<true, T> { /* empty */ };\n\ntemplate <typename Condition, typename T = void>\nstruct EnableIf : EnableIfCond<Condition::Value, T> {};\n\ntemplate <typename Condition, typename T = void>\nstruct DisableIf : DisableIfCond<Condition::Value, T> {};\n\n// SFINAE helpers\nstruct SfinaeTag {};\ntemplate <typename T> struct RemoveSfinaeTag;\ntemplate <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };\n\n#define RAPIDJSON_REMOVEFPTR_(type) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \\\n        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type\n\n#define RAPIDJSON_ENABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_DISABLEIF(cond) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL\n\n#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \\\n    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \\\n        <RAPIDJSON_REMOVEFPTR_(cond), \\\n         RAPIDJSON_REMOVEFPTR_(returntype)>::Type\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n//@endcond\n\n#if defined(__GNUC__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_META_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/pow10.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POW10_\n#define RAPIDJSON_POW10_\n\n#include \"../rapidjson.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Computes integer powers of 10 in double (10.0^n).\n/*! This function uses lookup table for fast and accurate results.\n    \\param n non-negative exponent. Must <= 308.\n    \\return 10.0^n\n*/\ninline double Pow10(int n) {\n    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes\n        1e+0,  \n        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, \n        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,\n        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,\n        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,\n        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,\n        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,\n        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,\n        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,\n        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,\n        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,\n        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,\n        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,\n        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,\n        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,\n        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,\n        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308\n    };\n    RAPIDJSON_ASSERT(n >= 0 && n <= 308);\n    return e[n];\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_POW10_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/regex.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_REGEX_H_\n#define RAPIDJSON_INTERNAL_REGEX_H_\n\n#include \"../allocators.h\"\n#include \"../stream.h\"\n#include \"stack.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\nRAPIDJSON_DIAG_OFF(implicit-fallthrough)\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\n#ifndef RAPIDJSON_REGEX_VERBOSE\n#define RAPIDJSON_REGEX_VERBOSE 0\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericRegex\n\nstatic const SizeType kRegexInvalidState = ~SizeType(0);  //!< Represents an invalid index in GenericRegex::State::out, out1\nstatic const SizeType kRegexInvalidRange = ~SizeType(0);\n\n//! Regular expression engine with subset of ECMAscript grammar.\n/*!\n    Supported regular expression syntax:\n    - \\c ab     Concatenation\n    - \\c a|b    Alternation\n    - \\c a?     Zero or one\n    - \\c a*     Zero or more\n    - \\c a+     One or more\n    - \\c a{3}   Exactly 3 times\n    - \\c a{3,}  At least 3 times\n    - \\c a{3,5} 3 to 5 times\n    - \\c (ab)   Grouping\n    - \\c ^a     At the beginning\n    - \\c a$     At the end\n    - \\c .      Any character\n    - \\c [abc]  Character classes\n    - \\c [a-c]  Character class range\n    - \\c [a-z0-9_] Character class combination\n    - \\c [^abc] Negated character classes\n    - \\c [^a-c] Negated character class range\n    - \\c [\\b]   Backspace (U+0008)\n    - \\c \\\\| \\\\\\\\ ...  Escape characters\n    - \\c \\\\f Form feed (U+000C)\n    - \\c \\\\n Line feed (U+000A)\n    - \\c \\\\r Carriage return (U+000D)\n    - \\c \\\\t Tab (U+0009)\n    - \\c \\\\v Vertical tab (U+000B)\n\n    \\note This is a Thompson NFA engine, implemented with reference to \n        Cox, Russ. \"Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).\", \n        https://swtch.com/~rsc/regexp/regexp1.html \n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nclass GenericRegex {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    GenericRegex(const Ch* source, Allocator* allocator = 0) : \n        states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), \n        stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()\n    {\n        GenericStringStream<Encoding> ss(source);\n        DecodedStream<GenericStringStream<Encoding> > ds(ss);\n        Parse(ds);\n    }\n\n    ~GenericRegex() {\n        Allocator::Free(stateSet_);\n    }\n\n    bool IsValid() const {\n        return root_ != kRegexInvalidState;\n    }\n\n    template <typename InputStream>\n    bool Match(InputStream& is) const {\n        return SearchWithAnchoring(is, true, true);\n    }\n\n    bool Match(const Ch* s) const {\n        GenericStringStream<Encoding> is(s);\n        return Match(is);\n    }\n\n    template <typename InputStream>\n    bool Search(InputStream& is) const {\n        return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);\n    }\n\n    bool Search(const Ch* s) const {\n        GenericStringStream<Encoding> is(s);\n        return Search(is);\n    }\n\nprivate:\n    enum Operator {\n        kZeroOrOne,\n        kZeroOrMore,\n        kOneOrMore,\n        kConcatenation,\n        kAlternation,\n        kLeftParenthesis\n    };\n\n    static const unsigned kAnyCharacterClass = 0xFFFFFFFF;   //!< For '.'\n    static const unsigned kRangeCharacterClass = 0xFFFFFFFE;\n    static const unsigned kRangeNegationFlag = 0x80000000;\n\n    struct Range {\n        unsigned start; // \n        unsigned end;\n        SizeType next;\n    };\n\n    struct State {\n        SizeType out;     //!< Equals to kInvalid for matching state\n        SizeType out1;    //!< Equals to non-kInvalid for split\n        SizeType rangeStart;\n        unsigned codepoint;\n    };\n\n    struct Frag {\n        Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}\n        SizeType start;\n        SizeType out; //!< link-list of all output states\n        SizeType minIndex;\n    };\n\n    template <typename SourceStream>\n    class DecodedStream {\n    public:\n        DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }\n        unsigned Peek() { return codepoint_; }\n        unsigned Take() {\n            unsigned c = codepoint_;\n            if (c) // No further decoding when '\\0'\n                Decode();\n            return c;\n        }\n\n    private:\n        void Decode() {\n            if (!Encoding::Decode(ss_, &codepoint_))\n                codepoint_ = 0;\n        }\n\n        SourceStream& ss_;\n        unsigned codepoint_;\n    };\n\n    State& GetState(SizeType index) {\n        RAPIDJSON_ASSERT(index < stateCount_);\n        return states_.template Bottom<State>()[index];\n    }\n\n    const State& GetState(SizeType index) const {\n        RAPIDJSON_ASSERT(index < stateCount_);\n        return states_.template Bottom<State>()[index];\n    }\n\n    Range& GetRange(SizeType index) {\n        RAPIDJSON_ASSERT(index < rangeCount_);\n        return ranges_.template Bottom<Range>()[index];\n    }\n\n    const Range& GetRange(SizeType index) const {\n        RAPIDJSON_ASSERT(index < rangeCount_);\n        return ranges_.template Bottom<Range>()[index];\n    }\n\n    template <typename InputStream>\n    void Parse(DecodedStream<InputStream>& ds) {\n        Allocator allocator;\n        Stack<Allocator> operandStack(&allocator, 256);     // Frag\n        Stack<Allocator> operatorStack(&allocator, 256);    // Operator\n        Stack<Allocator> atomCountStack(&allocator, 256);   // unsigned (Atom per parenthesis)\n\n        *atomCountStack.template Push<unsigned>() = 0;\n\n        unsigned codepoint;\n        while (ds.Peek() != 0) {\n            switch (codepoint = ds.Take()) {\n                case '^':\n                    anchorBegin_ = true;\n                    break;\n\n                case '$':\n                    anchorEnd_ = true;\n                    break;\n\n                case '|':\n                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)\n                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                            return;\n                    *operatorStack.template Push<Operator>() = kAlternation;\n                    *atomCountStack.template Top<unsigned>() = 0;\n                    break;\n\n                case '(':\n                    *operatorStack.template Push<Operator>() = kLeftParenthesis;\n                    *atomCountStack.template Push<unsigned>() = 0;\n                    break;\n\n                case ')':\n                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)\n                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                            return;\n                    if (operatorStack.Empty())\n                        return;\n                    operatorStack.template Pop<Operator>(1);\n                    atomCountStack.template Pop<unsigned>(1);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '?':\n                    if (!Eval(operandStack, kZeroOrOne))\n                        return;\n                    break;\n\n                case '*':\n                    if (!Eval(operandStack, kZeroOrMore))\n                        return;\n                    break;\n\n                case '+':\n                    if (!Eval(operandStack, kOneOrMore))\n                        return;\n                    break;\n\n                case '{':\n                    {\n                        unsigned n, m;\n                        if (!ParseUnsigned(ds, &n))\n                            return;\n\n                        if (ds.Peek() == ',') {\n                            ds.Take();\n                            if (ds.Peek() == '}')\n                                m = kInfinityQuantifier;\n                            else if (!ParseUnsigned(ds, &m) || m < n)\n                                return;\n                        }\n                        else\n                            m = n;\n\n                        if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')\n                            return;\n                        ds.Take();\n                    }\n                    break;\n\n                case '.':\n                    PushOperand(operandStack, kAnyCharacterClass);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '[':\n                    {\n                        SizeType range;\n                        if (!ParseRange(ds, &range))\n                            return;\n                        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);\n                        GetState(s).rangeStart = range;\n                        *operandStack.template Push<Frag>() = Frag(s, s, s);\n                    }\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n                    break;\n\n                case '\\\\': // Escape character\n                    if (!CharacterEscape(ds, &codepoint))\n                        return; // Unsupported escape character\n                    // fall through to default\n\n                default: // Pattern character\n                    PushOperand(operandStack, codepoint);\n                    ImplicitConcatenation(atomCountStack, operatorStack);\n            }\n        }\n\n        while (!operatorStack.Empty())\n            if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))\n                return;\n\n        // Link the operand to matching state.\n        if (operandStack.GetSize() == sizeof(Frag)) {\n            Frag* e = operandStack.template Pop<Frag>(1);\n            Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));\n            root_ = e->start;\n\n#if RAPIDJSON_REGEX_VERBOSE\n            printf(\"root: %d\\n\", root_);\n            for (SizeType i = 0; i < stateCount_ ; i++) {\n                State& s = GetState(i);\n                printf(\"[%2d] out: %2d out1: %2d c: '%c'\\n\", i, s.out, s.out1, (char)s.codepoint);\n            }\n            printf(\"\\n\");\n#endif\n        }\n\n        // Preallocate buffer for SearchWithAnchoring()\n        RAPIDJSON_ASSERT(stateSet_ == 0);\n        if (stateCount_ > 0) {\n            stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));\n            state0_.template Reserve<SizeType>(stateCount_);\n            state1_.template Reserve<SizeType>(stateCount_);\n        }\n    }\n\n    SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {\n        State* s = states_.template Push<State>();\n        s->out = out;\n        s->out1 = out1;\n        s->codepoint = codepoint;\n        s->rangeStart = kRegexInvalidRange;\n        return stateCount_++;\n    }\n\n    void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {\n        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);\n        *operandStack.template Push<Frag>() = Frag(s, s, s);\n    }\n\n    void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {\n        if (*atomCountStack.template Top<unsigned>())\n            *operatorStack.template Push<Operator>() = kConcatenation;\n        (*atomCountStack.template Top<unsigned>())++;\n    }\n\n    SizeType Append(SizeType l1, SizeType l2) {\n        SizeType old = l1;\n        while (GetState(l1).out != kRegexInvalidState)\n            l1 = GetState(l1).out;\n        GetState(l1).out = l2;\n        return old;\n    }\n\n    void Patch(SizeType l, SizeType s) {\n        for (SizeType next; l != kRegexInvalidState; l = next) {\n            next = GetState(l).out;\n            GetState(l).out = s;\n        }\n    }\n\n    bool Eval(Stack<Allocator>& operandStack, Operator op) {\n        switch (op) {\n            case kConcatenation:\n                RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);\n                {\n                    Frag e2 = *operandStack.template Pop<Frag>(1);\n                    Frag e1 = *operandStack.template Pop<Frag>(1);\n                    Patch(e1.out, e2.start);\n                    *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));\n                }\n                return true;\n\n            case kAlternation:\n                if (operandStack.GetSize() >= sizeof(Frag) * 2) {\n                    Frag e2 = *operandStack.template Pop<Frag>(1);\n                    Frag e1 = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(e1.start, e2.start, 0);\n                    *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));\n                    return true;\n                }\n                return false;\n\n            case kZeroOrOne:\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);\n                    return true;\n                }\n                return false;\n\n            case kZeroOrMore:\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    Patch(e.out, s);\n                    *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);\n                    return true;\n                }\n                return false;\n\n            default: \n                RAPIDJSON_ASSERT(op == kOneOrMore);\n                if (operandStack.GetSize() >= sizeof(Frag)) {\n                    Frag e = *operandStack.template Pop<Frag>(1);\n                    SizeType s = NewState(kRegexInvalidState, e.start, 0);\n                    Patch(e.out, s);\n                    *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);\n                    return true;\n                }\n                return false;\n        }\n    }\n\n    bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {\n        RAPIDJSON_ASSERT(n <= m);\n        RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));\n\n        if (n == 0) {\n            if (m == 0)                             // a{0} not support\n                return false;\n            else if (m == kInfinityQuantifier)\n                Eval(operandStack, kZeroOrMore);    // a{0,} -> a*\n            else {\n                Eval(operandStack, kZeroOrOne);         // a{0,5} -> a?\n                for (unsigned i = 0; i < m - 1; i++)\n                    CloneTopOperand(operandStack);      // a{0,5} -> a? a? a? a? a?\n                for (unsigned i = 0; i < m - 1; i++)\n                    Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?\n            }\n            return true;\n        }\n\n        for (unsigned i = 0; i < n - 1; i++)        // a{3} -> a a a\n            CloneTopOperand(operandStack);\n\n        if (m == kInfinityQuantifier)\n            Eval(operandStack, kOneOrMore);         // a{3,} -> a a a+\n        else if (m > n) {\n            CloneTopOperand(operandStack);          // a{3,5} -> a a a a\n            Eval(operandStack, kZeroOrOne);         // a{3,5} -> a a a a?\n            for (unsigned i = n; i < m - 1; i++)\n                CloneTopOperand(operandStack);      // a{3,5} -> a a a a? a?\n            for (unsigned i = n; i < m; i++)\n                Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?\n        }\n\n        for (unsigned i = 0; i < n - 1; i++)\n            Eval(operandStack, kConcatenation);     // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?\n\n        return true;\n    }\n\n    static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }\n\n    void CloneTopOperand(Stack<Allocator>& operandStack) {\n        const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation\n        SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)\n        State* s = states_.template Push<State>(count);\n        memcpy(s, &GetState(src.minIndex), count * sizeof(State));\n        for (SizeType j = 0; j < count; j++) {\n            if (s[j].out != kRegexInvalidState)\n                s[j].out += count;\n            if (s[j].out1 != kRegexInvalidState)\n                s[j].out1 += count;\n        }\n        *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);\n        stateCount_ += count;\n    }\n\n    template <typename InputStream>\n    bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {\n        unsigned r = 0;\n        if (ds.Peek() < '0' || ds.Peek() > '9')\n            return false;\n        while (ds.Peek() >= '0' && ds.Peek() <= '9') {\n            if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295\n                return false; // overflow\n            r = r * 10 + (ds.Take() - '0');\n        }\n        *u = r;\n        return true;\n    }\n\n    template <typename InputStream>\n    bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {\n        bool isBegin = true;\n        bool negate = false;\n        int step = 0;\n        SizeType start = kRegexInvalidRange;\n        SizeType current = kRegexInvalidRange;\n        unsigned codepoint;\n        while ((codepoint = ds.Take()) != 0) {\n            if (isBegin) {\n                isBegin = false;\n                if (codepoint == '^') {\n                    negate = true;\n                    continue;\n                }\n            }\n\n            switch (codepoint) {\n            case ']':\n                if (start == kRegexInvalidRange)\n                    return false;   // Error: nothing inside []\n                if (step == 2) { // Add trailing '-'\n                    SizeType r = NewRange('-');\n                    RAPIDJSON_ASSERT(current != kRegexInvalidRange);\n                    GetRange(current).next = r;\n                }\n                if (negate)\n                    GetRange(start).start |= kRangeNegationFlag;\n                *range = start;\n                return true;\n\n            case '\\\\':\n                if (ds.Peek() == 'b') {\n                    ds.Take();\n                    codepoint = 0x0008; // Escape backspace character\n                }\n                else if (!CharacterEscape(ds, &codepoint))\n                    return false;\n                // fall through to default\n\n            default:\n                switch (step) {\n                case 1:\n                    if (codepoint == '-') {\n                        step++;\n                        break;\n                    }\n                    // fall through to step 0 for other characters\n\n                case 0:\n                    {\n                        SizeType r = NewRange(codepoint);\n                        if (current != kRegexInvalidRange)\n                            GetRange(current).next = r;\n                        if (start == kRegexInvalidRange)\n                            start = r;\n                        current = r;\n                    }\n                    step = 1;\n                    break;\n\n                default:\n                    RAPIDJSON_ASSERT(step == 2);\n                    GetRange(current).end = codepoint;\n                    step = 0;\n                }\n            }\n        }\n        return false;\n    }\n    \n    SizeType NewRange(unsigned codepoint) {\n        Range* r = ranges_.template Push<Range>();\n        r->start = r->end = codepoint;\n        r->next = kRegexInvalidRange;\n        return rangeCount_++;\n    }\n\n    template <typename InputStream>\n    bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {\n        unsigned codepoint;\n        switch (codepoint = ds.Take()) {\n            case '^':\n            case '$':\n            case '|':\n            case '(':\n            case ')':\n            case '?':\n            case '*':\n            case '+':\n            case '.':\n            case '[':\n            case ']':\n            case '{':\n            case '}':\n            case '\\\\':\n                *escapedCodepoint = codepoint; return true;\n            case 'f': *escapedCodepoint = 0x000C; return true;\n            case 'n': *escapedCodepoint = 0x000A; return true;\n            case 'r': *escapedCodepoint = 0x000D; return true;\n            case 't': *escapedCodepoint = 0x0009; return true;\n            case 'v': *escapedCodepoint = 0x000B; return true;\n            default:\n                return false; // Unsupported escape character\n        }\n    }\n\n    template <typename InputStream>\n    bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {\n        RAPIDJSON_ASSERT(IsValid());\n        DecodedStream<InputStream> ds(is);\n\n        state0_.Clear();\n        Stack<Allocator> *current = &state0_, *next = &state1_;\n        const size_t stateSetSize = GetStateSetSize();\n        std::memset(stateSet_, 0, stateSetSize);\n\n        bool matched = AddState(*current, root_);\n        unsigned codepoint;\n        while (!current->Empty() && (codepoint = ds.Take()) != 0) {\n            std::memset(stateSet_, 0, stateSetSize);\n            next->Clear();\n            matched = false;\n            for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {\n                const State& sr = GetState(*s);\n                if (sr.codepoint == codepoint ||\n                    sr.codepoint == kAnyCharacterClass || \n                    (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))\n                {\n                    matched = AddState(*next, sr.out) || matched;\n                    if (!anchorEnd && matched)\n                        return true;\n                }\n                if (!anchorBegin)\n                    AddState(*next, root_);\n            }\n            internal::Swap(current, next);\n        }\n\n        return matched;\n    }\n\n    size_t GetStateSetSize() const {\n        return (stateCount_ + 31) / 32 * 4;\n    }\n\n    // Return whether the added states is a match state\n    bool AddState(Stack<Allocator>& l, SizeType index) const {\n        RAPIDJSON_ASSERT(index != kRegexInvalidState);\n\n        const State& s = GetState(index);\n        if (s.out1 != kRegexInvalidState) { // Split\n            bool matched = AddState(l, s.out);\n            return AddState(l, s.out1) || matched;\n        }\n        else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {\n            stateSet_[index >> 5] |= (1 << (index & 31));\n            *l.template PushUnsafe<SizeType>() = index;\n        }\n        return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.\n    }\n\n    bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {\n        bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;\n        while (rangeIndex != kRegexInvalidRange) {\n            const Range& r = GetRange(rangeIndex);\n            if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)\n                return yes;\n            rangeIndex = r.next;\n        }\n        return !yes;\n    }\n\n    Stack<Allocator> states_;\n    Stack<Allocator> ranges_;\n    SizeType root_;\n    SizeType stateCount_;\n    SizeType rangeCount_;\n\n    static const unsigned kInfinityQuantifier = ~0u;\n\n    // For SearchWithAnchoring()\n    uint32_t* stateSet_;        // allocated by states_.GetAllocator()\n    mutable Stack<Allocator> state0_;\n    mutable Stack<Allocator> state1_;\n    bool anchorBegin_;\n    bool anchorEnd_;\n};\n\ntypedef GenericRegex<UTF8<> > Regex;\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_REGEX_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/stack.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STACK_H_\n#define RAPIDJSON_INTERNAL_STACK_H_\n\n#include \"../allocators.h\"\n#include \"swap.h\"\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n///////////////////////////////////////////////////////////////////////////////\n// Stack\n\n//! A type-unsafe stack for storing different types of data.\n/*! \\tparam Allocator Allocator for allocating stack memory.\n*/\ntemplate <typename Allocator>\nclass Stack {\npublic:\n    // Optimization note: Do not allocate memory for stack_ in constructor.\n    // Do it lazily when first Push() -> Expand() -> Resize().\n    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack(Stack&& rhs)\n        : allocator_(rhs.allocator_),\n          ownAllocator_(rhs.ownAllocator_),\n          stack_(rhs.stack_),\n          stackTop_(rhs.stackTop_),\n          stackEnd_(rhs.stackEnd_),\n          initialCapacity_(rhs.initialCapacity_)\n    {\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n        rhs.stack_ = 0;\n        rhs.stackTop_ = 0;\n        rhs.stackEnd_ = 0;\n        rhs.initialCapacity_ = 0;\n    }\n#endif\n\n    ~Stack() {\n        Destroy();\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    Stack& operator=(Stack&& rhs) {\n        if (&rhs != this)\n        {\n            Destroy();\n\n            allocator_ = rhs.allocator_;\n            ownAllocator_ = rhs.ownAllocator_;\n            stack_ = rhs.stack_;\n            stackTop_ = rhs.stackTop_;\n            stackEnd_ = rhs.stackEnd_;\n            initialCapacity_ = rhs.initialCapacity_;\n\n            rhs.allocator_ = 0;\n            rhs.ownAllocator_ = 0;\n            rhs.stack_ = 0;\n            rhs.stackTop_ = 0;\n            rhs.stackEnd_ = 0;\n            rhs.initialCapacity_ = 0;\n        }\n        return *this;\n    }\n#endif\n\n    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {\n        internal::Swap(allocator_, rhs.allocator_);\n        internal::Swap(ownAllocator_, rhs.ownAllocator_);\n        internal::Swap(stack_, rhs.stack_);\n        internal::Swap(stackTop_, rhs.stackTop_);\n        internal::Swap(stackEnd_, rhs.stackEnd_);\n        internal::Swap(initialCapacity_, rhs.initialCapacity_);\n    }\n\n    void Clear() { stackTop_ = stack_; }\n\n    void ShrinkToFit() { \n        if (Empty()) {\n            // If the stack is empty, completely deallocate the memory.\n            Allocator::Free(stack_);\n            stack_ = 0;\n            stackTop_ = 0;\n            stackEnd_ = 0;\n        }\n        else\n            Resize(GetSize());\n    }\n\n    // Optimization note: try to minimize the size of this function for force inline.\n    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.\n    template<typename T>\n    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {\n         // Expand the stack if needed\n        if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))\n            Expand<T>(count);\n    }\n\n    template<typename T>\n    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {\n        Reserve<T>(count);\n        return PushUnsafe<T>(count);\n    }\n\n    template<typename T>\n    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {\n        RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);\n        T* ret = reinterpret_cast<T*>(stackTop_);\n        stackTop_ += sizeof(T) * count;\n        return ret;\n    }\n\n    template<typename T>\n    T* Pop(size_t count) {\n        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));\n        stackTop_ -= count * sizeof(T);\n        return reinterpret_cast<T*>(stackTop_);\n    }\n\n    template<typename T>\n    T* Top() { \n        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n        return reinterpret_cast<T*>(stackTop_ - sizeof(T));\n    }\n\n    template<typename T>\n    const T* Top() const {\n        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));\n        return reinterpret_cast<T*>(stackTop_ - sizeof(T));\n    }\n\n    template<typename T>\n    T* End() { return reinterpret_cast<T*>(stackTop_); }\n\n    template<typename T>\n    const T* End() const { return reinterpret_cast<T*>(stackTop_); }\n\n    template<typename T>\n    T* Bottom() { return reinterpret_cast<T*>(stack_); }\n\n    template<typename T>\n    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }\n\n    bool HasAllocator() const {\n        return allocator_ != 0;\n    }\n\n    Allocator& GetAllocator() {\n        RAPIDJSON_ASSERT(allocator_);\n        return *allocator_;\n    }\n\n    bool Empty() const { return stackTop_ == stack_; }\n    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }\n    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }\n\nprivate:\n    template<typename T>\n    void Expand(size_t count) {\n        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.\n        size_t newCapacity;\n        if (stack_ == 0) {\n            if (!allocator_)\n                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n            newCapacity = initialCapacity_;\n        } else {\n            newCapacity = GetCapacity();\n            newCapacity += (newCapacity + 1) / 2;\n        }\n        size_t newSize = GetSize() + sizeof(T) * count;\n        if (newCapacity < newSize)\n            newCapacity = newSize;\n\n        Resize(newCapacity);\n    }\n\n    void Resize(size_t newCapacity) {\n        const size_t size = GetSize();  // Backup the current size\n        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));\n        stackTop_ = stack_ + size;\n        stackEnd_ = stack_ + newCapacity;\n    }\n\n    void Destroy() {\n        Allocator::Free(stack_);\n        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack\n    }\n\n    // Prohibit copy constructor & assignment operator.\n    Stack(const Stack&);\n    Stack& operator=(const Stack&);\n\n    Allocator* allocator_;\n    Allocator* ownAllocator_;\n    char *stack_;\n    char *stackTop_;\n    char *stackEnd_;\n    size_t initialCapacity_;\n};\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_STACK_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/strfunc.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_\n#define RAPIDJSON_INTERNAL_STRFUNC_H_\n\n#include \"../stream.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Custom strlen() which works on different character types.\n/*! \\tparam Ch Character type (e.g. char, wchar_t, short)\n    \\param s Null-terminated input string.\n    \\return Number of characters in the string. \n    \\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.\n*/\ntemplate <typename Ch>\ninline SizeType StrLen(const Ch* s) {\n    const Ch* p = s;\n    while (*p) ++p;\n    return SizeType(p - s);\n}\n\n//! Returns number of code points in a encoded string.\ntemplate<typename Encoding>\nbool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {\n    GenericStringStream<Encoding> is(s);\n    const typename Encoding::Ch* end = s + length;\n    SizeType count = 0;\n    while (is.src_ < end) {\n        unsigned codepoint;\n        if (!Encoding::Decode(is, &codepoint))\n            return false;\n        count++;\n    }\n    *outCount = count;\n    return true;\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_INTERNAL_STRFUNC_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/strtod.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRTOD_\n#define RAPIDJSON_STRTOD_\n\n#include \"ieee754.h\"\n#include \"biginteger.h\"\n#include \"diyfp.h\"\n#include \"pow10.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\ninline double FastPath(double significand, int exp) {\n    if (exp < -308)\n        return 0.0;\n    else if (exp >= 0)\n        return significand * internal::Pow10(exp);\n    else\n        return significand / internal::Pow10(-exp);\n}\n\ninline double StrtodNormalPrecision(double d, int p) {\n    if (p < -308) {\n        // Prevent expSum < -308, making Pow10(p) = 0\n        d = FastPath(d, -308);\n        d = FastPath(d, p + 308);\n    }\n    else\n        d = FastPath(d, p);\n    return d;\n}\n\ntemplate <typename T>\ninline T Min3(T a, T b, T c) {\n    T m = a;\n    if (m > b) m = b;\n    if (m > c) m = c;\n    return m;\n}\n\ninline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {\n    const Double db(b);\n    const uint64_t bInt = db.IntegerSignificand();\n    const int bExp = db.IntegerExponent();\n    const int hExp = bExp - 1;\n\n    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;\n\n    // Adjust for decimal exponent\n    if (dExp >= 0) {\n        dS_Exp2 += dExp;\n        dS_Exp5 += dExp;\n    }\n    else {\n        bS_Exp2 -= dExp;\n        bS_Exp5 -= dExp;\n        hS_Exp2 -= dExp;\n        hS_Exp5 -= dExp;\n    }\n\n    // Adjust for binary exponent\n    if (bExp >= 0)\n        bS_Exp2 += bExp;\n    else {\n        dS_Exp2 -= bExp;\n        hS_Exp2 -= bExp;\n    }\n\n    // Adjust for half ulp exponent\n    if (hExp >= 0)\n        hS_Exp2 += hExp;\n    else {\n        dS_Exp2 -= hExp;\n        bS_Exp2 -= hExp;\n    }\n\n    // Remove common power of two factor from all three scaled values\n    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);\n    dS_Exp2 -= common_Exp2;\n    bS_Exp2 -= common_Exp2;\n    hS_Exp2 -= common_Exp2;\n\n    BigInteger dS = d;\n    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);\n\n    BigInteger bS(bInt);\n    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);\n\n    BigInteger hS(1);\n    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);\n\n    BigInteger delta(0);\n    dS.Difference(bS, &delta);\n\n    return delta.Compare(hS);\n}\n\ninline bool StrtodFast(double d, int p, double* result) {\n    // Use fast path for string-to-double conversion if possible\n    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/\n    if (p > 22  && p < 22 + 16) {\n        // Fast Path Cases In Disguise\n        d *= internal::Pow10(p - 22);\n        p = 22;\n    }\n\n    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1\n        *result = FastPath(d, p);\n        return true;\n    }\n    else\n        return false;\n}\n\n// Compute an approximation and see if it is within 1/2 ULP\ninline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {\n    uint64_t significand = 0;\n    size_t i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    \n    for (; i < length; i++) {\n        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||\n            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))\n            break;\n        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');\n    }\n    \n    if (i < length && decimals[i] >= '5') // Rounding\n        significand++;\n\n    size_t remaining = length - i;\n    const unsigned kUlpShift = 3;\n    const unsigned kUlp = 1 << kUlpShift;\n    int64_t error = (remaining == 0) ? 0 : kUlp / 2;\n\n    DiyFp v(significand, 0);\n    v = v.Normalize();\n    error <<= -v.e;\n\n    const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;\n\n    int actualExp;\n    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);\n    if (actualExp != dExp) {\n        static const DiyFp kPow10[] = {\n            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60),  // 10^1\n            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57),  // 10^2\n            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54),  // 10^3\n            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50),  // 10^4\n            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47),  // 10^5\n            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44),  // 10^6\n            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40)   // 10^7\n        };\n        int  adjustment = dExp - actualExp - 1;\n        RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);\n        v = v * kPow10[adjustment];\n        if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit\n            error += kUlp / 2;\n    }\n\n    v = v * cachedPower;\n\n    error += kUlp + (error == 0 ? 0 : 1);\n\n    const int oldExp = v.e;\n    v = v.Normalize();\n    error <<= oldExp - v.e;\n\n    const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);\n    unsigned precisionSize = 64 - effectiveSignificandSize;\n    if (precisionSize + kUlpShift >= 64) {\n        unsigned scaleExp = (precisionSize + kUlpShift) - 63;\n        v.f >>= scaleExp;\n        v.e += scaleExp; \n        error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);\n        precisionSize -= scaleExp;\n    }\n\n    DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));\n    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;\n    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;\n    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {\n        rounded.f++;\n        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)\n            rounded.f >>= 1;\n            rounded.e++;\n        }\n    }\n\n    *result = rounded.ToDouble();\n\n    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);\n}\n\ninline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {\n    const BigInteger dInt(decimals, length);\n    const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;\n    Double a(approx);\n    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);\n    if (cmp < 0)\n        return a.Value();  // within half ULP\n    else if (cmp == 0) {\n        // Round towards even\n        if (a.Significand() & 1)\n            return a.NextPositiveDouble();\n        else\n            return a.Value();\n    }\n    else // adjustment\n        return a.NextPositiveDouble();\n}\n\ninline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {\n    RAPIDJSON_ASSERT(d >= 0.0);\n    RAPIDJSON_ASSERT(length >= 1);\n\n    double result;\n    if (StrtodFast(d, p, &result))\n        return result;\n\n    // Trim leading zeros\n    while (*decimals == '0' && length > 1) {\n        length--;\n        decimals++;\n        decimalPosition--;\n    }\n\n    // Trim trailing zeros\n    while (decimals[length - 1] == '0' && length > 1) {\n        length--;\n        decimalPosition--;\n        exp++;\n    }\n\n    // Trim right-most digits\n    const int kMaxDecimalDigit = 780;\n    if (static_cast<int>(length) > kMaxDecimalDigit) {\n        int delta = (static_cast<int>(length) - kMaxDecimalDigit);\n        exp += delta;\n        decimalPosition -= static_cast<unsigned>(delta);\n        length = kMaxDecimalDigit;\n    }\n\n    // If too small, underflow to zero\n    if (int(length) + exp < -324)\n        return 0.0;\n\n    if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))\n        return result;\n\n    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison\n    return StrtodBigInteger(result, decimals, length, decimalPosition, exp);\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STRTOD_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/internal/swap.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_INTERNAL_SWAP_H_\n#define RAPIDJSON_INTERNAL_SWAP_H_\n\n#include \"../rapidjson.h\"\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\nnamespace internal {\n\n//! Custom swap() to avoid dependency on C++ <algorithm> header\n/*! \\tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.\n    \\note This has the same semantics as std::swap().\n*/\ntemplate <typename T>\ninline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {\n    T tmp = a;\n        a = b;\n        b = tmp;\n}\n\n} // namespace internal\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_INTERNAL_SWAP_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/istreamwrapper.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_ISTREAMWRAPPER_H_\n#define RAPIDJSON_ISTREAMWRAPPER_H_\n\n#include \"stream.h\"\n#include <iosfwd>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of \\c std::basic_istream into RapidJSON's Stream concept.\n/*!\n    The classes can be wrapped including but not limited to:\n\n    - \\c std::istringstream\n    - \\c std::stringstream\n    - \\c std::wistringstream\n    - \\c std::wstringstream\n    - \\c std::ifstream\n    - \\c std::fstream\n    - \\c std::wifstream\n    - \\c std::wfstream\n\n    \\tparam StreamType Class derived from \\c std::basic_istream.\n*/\n   \ntemplate <typename StreamType>\nclass BasicIStreamWrapper {\npublic:\n    typedef typename StreamType::char_type Ch;\n    BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}\n\n    Ch Peek() const { \n        typename StreamType::int_type c = stream_.peek();\n        return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\\0';\n    }\n\n    Ch Take() { \n        typename StreamType::int_type c = stream_.get();\n        if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {\n            count_++;\n            return static_cast<Ch>(c);\n        }\n        else\n            return '\\0';\n    }\n\n    // tellg() may return -1 when failed. So we count by ourself.\n    size_t Tell() const { return count_; }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.\n        int i;\n        bool hasError = false;\n        for (i = 0; i < 4; ++i) {\n            typename StreamType::int_type c = stream_.get();\n            if (c == StreamType::traits_type::eof()) {\n                hasError = true;\n                stream_.clear();\n                break;\n            }\n            peekBuffer_[i] = static_cast<Ch>(c);\n        }\n        for (--i; i >= 0; --i)\n            stream_.putback(peekBuffer_[i]);\n        return !hasError ? peekBuffer_ : 0;\n    }\n\nprivate:\n    BasicIStreamWrapper(const BasicIStreamWrapper&);\n    BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);\n\n    StreamType& stream_;\n    size_t count_;  //!< Number of characters read. Note:\n    mutable Ch peekBuffer_[4];\n};\n\ntypedef BasicIStreamWrapper<std::istream> IStreamWrapper;\ntypedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;\n\n#if defined(__clang__) || defined(_MSC_VER)\nRAPIDJSON_DIAG_POP\n#endif\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_ISTREAMWRAPPER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/memorybuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYBUFFER_H_\n#define RAPIDJSON_MEMORYBUFFER_H_\n\n#include \"stream.h\"\n#include \"internal/stack.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.\n\n    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.\n\n    Differences between MemoryBuffer and StringBuffer:\n    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. \n    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.\n\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Allocator = CrtAllocator>\nstruct GenericMemoryBuffer {\n    typedef char Ch; // byte\n\n    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() { stack_.ShrinkToFit(); }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetBuffer() const {\n        return stack_.template Bottom<Ch>();\n    }\n\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n};\n\ntypedef GenericMemoryBuffer<> MemoryBuffer;\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {\n    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/memorystream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_MEMORYSTREAM_H_\n#define RAPIDJSON_MEMORYSTREAM_H_\n\n#include \"stream.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(unreachable-code)\nRAPIDJSON_DIAG_OFF(missing-noreturn)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory input byte stream.\n/*!\n    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.\n\n    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.\n\n    Differences between MemoryStream and StringStream:\n    1. StringStream has encoding but MemoryStream is a byte stream.\n    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.\n    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().\n    \\note implements Stream concept\n*/\nstruct MemoryStream {\n    typedef char Ch; // byte\n\n    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}\n\n    Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\\0' : *src_; }\n    Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\\0' : *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    // For encoding detection only.\n    const Ch* Peek4() const {\n        return Tell() + 4 <= size_ ? src_ : 0;\n    }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* begin_;   //!< Original head of the string.\n    const Ch* end_;     //!< End of stream.\n    size_t size_;       //!< Size of the stream.\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_MEMORYBUFFER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/msinttypes/inttypes.h",
    "content": "// ISO C9x  compliant inttypes.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// \n//   1. Redistributions of source code must retain the above copyright notice,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_INTTYPES_H_ // [\n#define _MSC_INTTYPES_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n#include \"stdint.h\"\n\n// miloyip: VC supports inttypes.h since VC2013\n#if _MSC_VER >= 1800\n#include <inttypes.h>\n#else\n\n// 7.8 Format conversion of integer types\n\ntypedef struct {\n   intmax_t quot;\n   intmax_t rem;\n} imaxdiv_t;\n\n// 7.8.1 Macros for format specifiers\n\n#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198\n\n// The fprintf macros for signed integers are:\n#define PRId8       \"d\"\n#define PRIi8       \"i\"\n#define PRIdLEAST8  \"d\"\n#define PRIiLEAST8  \"i\"\n#define PRIdFAST8   \"d\"\n#define PRIiFAST8   \"i\"\n\n#define PRId16       \"hd\"\n#define PRIi16       \"hi\"\n#define PRIdLEAST16  \"hd\"\n#define PRIiLEAST16  \"hi\"\n#define PRIdFAST16   \"hd\"\n#define PRIiFAST16   \"hi\"\n\n#define PRId32       \"I32d\"\n#define PRIi32       \"I32i\"\n#define PRIdLEAST32  \"I32d\"\n#define PRIiLEAST32  \"I32i\"\n#define PRIdFAST32   \"I32d\"\n#define PRIiFAST32   \"I32i\"\n\n#define PRId64       \"I64d\"\n#define PRIi64       \"I64i\"\n#define PRIdLEAST64  \"I64d\"\n#define PRIiLEAST64  \"I64i\"\n#define PRIdFAST64   \"I64d\"\n#define PRIiFAST64   \"I64i\"\n\n#define PRIdMAX     \"I64d\"\n#define PRIiMAX     \"I64i\"\n\n#define PRIdPTR     \"Id\"\n#define PRIiPTR     \"Ii\"\n\n// The fprintf macros for unsigned integers are:\n#define PRIo8       \"o\"\n#define PRIu8       \"u\"\n#define PRIx8       \"x\"\n#define PRIX8       \"X\"\n#define PRIoLEAST8  \"o\"\n#define PRIuLEAST8  \"u\"\n#define PRIxLEAST8  \"x\"\n#define PRIXLEAST8  \"X\"\n#define PRIoFAST8   \"o\"\n#define PRIuFAST8   \"u\"\n#define PRIxFAST8   \"x\"\n#define PRIXFAST8   \"X\"\n\n#define PRIo16       \"ho\"\n#define PRIu16       \"hu\"\n#define PRIx16       \"hx\"\n#define PRIX16       \"hX\"\n#define PRIoLEAST16  \"ho\"\n#define PRIuLEAST16  \"hu\"\n#define PRIxLEAST16  \"hx\"\n#define PRIXLEAST16  \"hX\"\n#define PRIoFAST16   \"ho\"\n#define PRIuFAST16   \"hu\"\n#define PRIxFAST16   \"hx\"\n#define PRIXFAST16   \"hX\"\n\n#define PRIo32       \"I32o\"\n#define PRIu32       \"I32u\"\n#define PRIx32       \"I32x\"\n#define PRIX32       \"I32X\"\n#define PRIoLEAST32  \"I32o\"\n#define PRIuLEAST32  \"I32u\"\n#define PRIxLEAST32  \"I32x\"\n#define PRIXLEAST32  \"I32X\"\n#define PRIoFAST32   \"I32o\"\n#define PRIuFAST32   \"I32u\"\n#define PRIxFAST32   \"I32x\"\n#define PRIXFAST32   \"I32X\"\n\n#define PRIo64       \"I64o\"\n#define PRIu64       \"I64u\"\n#define PRIx64       \"I64x\"\n#define PRIX64       \"I64X\"\n#define PRIoLEAST64  \"I64o\"\n#define PRIuLEAST64  \"I64u\"\n#define PRIxLEAST64  \"I64x\"\n#define PRIXLEAST64  \"I64X\"\n#define PRIoFAST64   \"I64o\"\n#define PRIuFAST64   \"I64u\"\n#define PRIxFAST64   \"I64x\"\n#define PRIXFAST64   \"I64X\"\n\n#define PRIoMAX     \"I64o\"\n#define PRIuMAX     \"I64u\"\n#define PRIxMAX     \"I64x\"\n#define PRIXMAX     \"I64X\"\n\n#define PRIoPTR     \"Io\"\n#define PRIuPTR     \"Iu\"\n#define PRIxPTR     \"Ix\"\n#define PRIXPTR     \"IX\"\n\n// The fscanf macros for signed integers are:\n#define SCNd8       \"d\"\n#define SCNi8       \"i\"\n#define SCNdLEAST8  \"d\"\n#define SCNiLEAST8  \"i\"\n#define SCNdFAST8   \"d\"\n#define SCNiFAST8   \"i\"\n\n#define SCNd16       \"hd\"\n#define SCNi16       \"hi\"\n#define SCNdLEAST16  \"hd\"\n#define SCNiLEAST16  \"hi\"\n#define SCNdFAST16   \"hd\"\n#define SCNiFAST16   \"hi\"\n\n#define SCNd32       \"ld\"\n#define SCNi32       \"li\"\n#define SCNdLEAST32  \"ld\"\n#define SCNiLEAST32  \"li\"\n#define SCNdFAST32   \"ld\"\n#define SCNiFAST32   \"li\"\n\n#define SCNd64       \"I64d\"\n#define SCNi64       \"I64i\"\n#define SCNdLEAST64  \"I64d\"\n#define SCNiLEAST64  \"I64i\"\n#define SCNdFAST64   \"I64d\"\n#define SCNiFAST64   \"I64i\"\n\n#define SCNdMAX     \"I64d\"\n#define SCNiMAX     \"I64i\"\n\n#ifdef _WIN64 // [\n#  define SCNdPTR     \"I64d\"\n#  define SCNiPTR     \"I64i\"\n#else  // _WIN64 ][\n#  define SCNdPTR     \"ld\"\n#  define SCNiPTR     \"li\"\n#endif  // _WIN64 ]\n\n// The fscanf macros for unsigned integers are:\n#define SCNo8       \"o\"\n#define SCNu8       \"u\"\n#define SCNx8       \"x\"\n#define SCNX8       \"X\"\n#define SCNoLEAST8  \"o\"\n#define SCNuLEAST8  \"u\"\n#define SCNxLEAST8  \"x\"\n#define SCNXLEAST8  \"X\"\n#define SCNoFAST8   \"o\"\n#define SCNuFAST8   \"u\"\n#define SCNxFAST8   \"x\"\n#define SCNXFAST8   \"X\"\n\n#define SCNo16       \"ho\"\n#define SCNu16       \"hu\"\n#define SCNx16       \"hx\"\n#define SCNX16       \"hX\"\n#define SCNoLEAST16  \"ho\"\n#define SCNuLEAST16  \"hu\"\n#define SCNxLEAST16  \"hx\"\n#define SCNXLEAST16  \"hX\"\n#define SCNoFAST16   \"ho\"\n#define SCNuFAST16   \"hu\"\n#define SCNxFAST16   \"hx\"\n#define SCNXFAST16   \"hX\"\n\n#define SCNo32       \"lo\"\n#define SCNu32       \"lu\"\n#define SCNx32       \"lx\"\n#define SCNX32       \"lX\"\n#define SCNoLEAST32  \"lo\"\n#define SCNuLEAST32  \"lu\"\n#define SCNxLEAST32  \"lx\"\n#define SCNXLEAST32  \"lX\"\n#define SCNoFAST32   \"lo\"\n#define SCNuFAST32   \"lu\"\n#define SCNxFAST32   \"lx\"\n#define SCNXFAST32   \"lX\"\n\n#define SCNo64       \"I64o\"\n#define SCNu64       \"I64u\"\n#define SCNx64       \"I64x\"\n#define SCNX64       \"I64X\"\n#define SCNoLEAST64  \"I64o\"\n#define SCNuLEAST64  \"I64u\"\n#define SCNxLEAST64  \"I64x\"\n#define SCNXLEAST64  \"I64X\"\n#define SCNoFAST64   \"I64o\"\n#define SCNuFAST64   \"I64u\"\n#define SCNxFAST64   \"I64x\"\n#define SCNXFAST64   \"I64X\"\n\n#define SCNoMAX     \"I64o\"\n#define SCNuMAX     \"I64u\"\n#define SCNxMAX     \"I64x\"\n#define SCNXMAX     \"I64X\"\n\n#ifdef _WIN64 // [\n#  define SCNoPTR     \"I64o\"\n#  define SCNuPTR     \"I64u\"\n#  define SCNxPTR     \"I64x\"\n#  define SCNXPTR     \"I64X\"\n#else  // _WIN64 ][\n#  define SCNoPTR     \"lo\"\n#  define SCNuPTR     \"lu\"\n#  define SCNxPTR     \"lx\"\n#  define SCNXPTR     \"lX\"\n#endif  // _WIN64 ]\n\n#endif // __STDC_FORMAT_MACROS ]\n\n// 7.8.2 Functions for greatest-width integer types\n\n// 7.8.2.1 The imaxabs function\n#define imaxabs _abs64\n\n// 7.8.2.2 The imaxdiv function\n\n// This is modified version of div() function from Microsoft's div.c found\n// in %MSVC.NET%\\crt\\src\\div.c\n#ifdef STATIC_IMAXDIV // [\nstatic\n#else // STATIC_IMAXDIV ][\n_inline\n#endif // STATIC_IMAXDIV ]\nimaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)\n{\n   imaxdiv_t result;\n\n   result.quot = numer / denom;\n   result.rem = numer % denom;\n\n   if (numer < 0 && result.rem > 0) {\n      // did division wrong; must fix up\n      ++result.quot;\n      result.rem -= denom;\n   }\n\n   return result;\n}\n\n// 7.8.2.3 The strtoimax and strtoumax functions\n#define strtoimax _strtoi64\n#define strtoumax _strtoui64\n\n// 7.8.2.4 The wcstoimax and wcstoumax functions\n#define wcstoimax _wcstoi64\n#define wcstoumax _wcstoui64\n\n#endif // _MSC_VER >= 1800\n\n#endif // _MSC_INTTYPES_H_ ]\n"
  },
  {
    "path": "src/thirdparty/rapidjson/msinttypes/stdint.h",
    "content": "// ISO C9x  compliant stdint.h for Microsoft Visual Studio\n// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 \n// \n//  Copyright (c) 2006-2013 Alexander Chemeris\n// \n// Redistribution and use in source and binary forms, with or without\n// modification, are permitted provided that the following conditions are met:\n// \n//   1. Redistributions of source code must retain the above copyright notice,\n//      this list of conditions and the following disclaimer.\n// \n//   2. Redistributions in binary form must reproduce the above copyright\n//      notice, this list of conditions and the following disclaimer in the\n//      documentation and/or other materials provided with the distribution.\n// \n//   3. Neither the name of the product nor the names of its contributors may\n//      be used to endorse or promote products derived from this software\n//      without specific prior written permission.\n// \n// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\n// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\n// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO\n// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;\n// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, \n// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\n// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n// \n///////////////////////////////////////////////////////////////////////////////\n\n// The above software in this distribution may have been modified by \n// THL A29 Limited (\"Tencent Modifications\"). \n// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.\n\n#ifndef _MSC_VER // [\n#error \"Use this header only with Microsoft Visual C++ compilers!\"\n#endif // _MSC_VER ]\n\n#ifndef _MSC_STDINT_H_ // [\n#define _MSC_STDINT_H_\n\n#if _MSC_VER > 1000\n#pragma once\n#endif\n\n// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.\n#if _MSC_VER >= 1600 // [\n#include <stdint.h>\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n#undef INT8_C\n#undef INT16_C\n#undef INT32_C\n#undef INT64_C\n#undef UINT8_C\n#undef UINT16_C\n#undef UINT32_C\n#undef UINT64_C\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#else // ] _MSC_VER >= 1700 [\n\n#include <limits.h>\n\n// For Visual Studio 6 in C++ mode and for many Visual Studio versions when\n// compiling for ARM we have to wrap <wchar.h> include with 'extern \"C++\" {}'\n// or compiler would give many errors like this:\n//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed\n#if defined(__cplusplus) && !defined(_M_ARM)\nextern \"C\" {\n#endif\n#  include <wchar.h>\n#if defined(__cplusplus) && !defined(_M_ARM)\n}\n#endif\n\n// Define _W64 macros to mark types changing their size, like intptr_t.\n#ifndef _W64\n#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300\n#     define _W64 __w64\n#  else\n#     define _W64\n#  endif\n#endif\n\n\n// 7.18.1 Integer types\n\n// 7.18.1.1 Exact-width integer types\n\n// Visual Studio 6 and Embedded Visual C++ 4 doesn't\n// realize that, e.g. char has the same size as __int8\n// so we give up on __intX for them.\n#if (_MSC_VER < 1300)\n   typedef signed char       int8_t;\n   typedef signed short      int16_t;\n   typedef signed int        int32_t;\n   typedef unsigned char     uint8_t;\n   typedef unsigned short    uint16_t;\n   typedef unsigned int      uint32_t;\n#else\n   typedef signed __int8     int8_t;\n   typedef signed __int16    int16_t;\n   typedef signed __int32    int32_t;\n   typedef unsigned __int8   uint8_t;\n   typedef unsigned __int16  uint16_t;\n   typedef unsigned __int32  uint32_t;\n#endif\ntypedef signed __int64       int64_t;\ntypedef unsigned __int64     uint64_t;\n\n\n// 7.18.1.2 Minimum-width integer types\ntypedef int8_t    int_least8_t;\ntypedef int16_t   int_least16_t;\ntypedef int32_t   int_least32_t;\ntypedef int64_t   int_least64_t;\ntypedef uint8_t   uint_least8_t;\ntypedef uint16_t  uint_least16_t;\ntypedef uint32_t  uint_least32_t;\ntypedef uint64_t  uint_least64_t;\n\n// 7.18.1.3 Fastest minimum-width integer types\ntypedef int8_t    int_fast8_t;\ntypedef int16_t   int_fast16_t;\ntypedef int32_t   int_fast32_t;\ntypedef int64_t   int_fast64_t;\ntypedef uint8_t   uint_fast8_t;\ntypedef uint16_t  uint_fast16_t;\ntypedef uint32_t  uint_fast32_t;\ntypedef uint64_t  uint_fast64_t;\n\n// 7.18.1.4 Integer types capable of holding object pointers\n#ifdef _WIN64 // [\n   typedef signed __int64    intptr_t;\n   typedef unsigned __int64  uintptr_t;\n#else // _WIN64 ][\n   typedef _W64 signed int   intptr_t;\n   typedef _W64 unsigned int uintptr_t;\n#endif // _WIN64 ]\n\n// 7.18.1.5 Greatest-width integer types\ntypedef int64_t   intmax_t;\ntypedef uint64_t  uintmax_t;\n\n\n// 7.18.2 Limits of specified-width integer types\n\n#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259\n\n// 7.18.2.1 Limits of exact-width integer types\n#define INT8_MIN     ((int8_t)_I8_MIN)\n#define INT8_MAX     _I8_MAX\n#define INT16_MIN    ((int16_t)_I16_MIN)\n#define INT16_MAX    _I16_MAX\n#define INT32_MIN    ((int32_t)_I32_MIN)\n#define INT32_MAX    _I32_MAX\n#define INT64_MIN    ((int64_t)_I64_MIN)\n#define INT64_MAX    _I64_MAX\n#define UINT8_MAX    _UI8_MAX\n#define UINT16_MAX   _UI16_MAX\n#define UINT32_MAX   _UI32_MAX\n#define UINT64_MAX   _UI64_MAX\n\n// 7.18.2.2 Limits of minimum-width integer types\n#define INT_LEAST8_MIN    INT8_MIN\n#define INT_LEAST8_MAX    INT8_MAX\n#define INT_LEAST16_MIN   INT16_MIN\n#define INT_LEAST16_MAX   INT16_MAX\n#define INT_LEAST32_MIN   INT32_MIN\n#define INT_LEAST32_MAX   INT32_MAX\n#define INT_LEAST64_MIN   INT64_MIN\n#define INT_LEAST64_MAX   INT64_MAX\n#define UINT_LEAST8_MAX   UINT8_MAX\n#define UINT_LEAST16_MAX  UINT16_MAX\n#define UINT_LEAST32_MAX  UINT32_MAX\n#define UINT_LEAST64_MAX  UINT64_MAX\n\n// 7.18.2.3 Limits of fastest minimum-width integer types\n#define INT_FAST8_MIN    INT8_MIN\n#define INT_FAST8_MAX    INT8_MAX\n#define INT_FAST16_MIN   INT16_MIN\n#define INT_FAST16_MAX   INT16_MAX\n#define INT_FAST32_MIN   INT32_MIN\n#define INT_FAST32_MAX   INT32_MAX\n#define INT_FAST64_MIN   INT64_MIN\n#define INT_FAST64_MAX   INT64_MAX\n#define UINT_FAST8_MAX   UINT8_MAX\n#define UINT_FAST16_MAX  UINT16_MAX\n#define UINT_FAST32_MAX  UINT32_MAX\n#define UINT_FAST64_MAX  UINT64_MAX\n\n// 7.18.2.4 Limits of integer types capable of holding object pointers\n#ifdef _WIN64 // [\n#  define INTPTR_MIN   INT64_MIN\n#  define INTPTR_MAX   INT64_MAX\n#  define UINTPTR_MAX  UINT64_MAX\n#else // _WIN64 ][\n#  define INTPTR_MIN   INT32_MIN\n#  define INTPTR_MAX   INT32_MAX\n#  define UINTPTR_MAX  UINT32_MAX\n#endif // _WIN64 ]\n\n// 7.18.2.5 Limits of greatest-width integer types\n#define INTMAX_MIN   INT64_MIN\n#define INTMAX_MAX   INT64_MAX\n#define UINTMAX_MAX  UINT64_MAX\n\n// 7.18.3 Limits of other integer types\n\n#ifdef _WIN64 // [\n#  define PTRDIFF_MIN  _I64_MIN\n#  define PTRDIFF_MAX  _I64_MAX\n#else  // _WIN64 ][\n#  define PTRDIFF_MIN  _I32_MIN\n#  define PTRDIFF_MAX  _I32_MAX\n#endif  // _WIN64 ]\n\n#define SIG_ATOMIC_MIN  INT_MIN\n#define SIG_ATOMIC_MAX  INT_MAX\n\n#ifndef SIZE_MAX // [\n#  ifdef _WIN64 // [\n#     define SIZE_MAX  _UI64_MAX\n#  else // _WIN64 ][\n#     define SIZE_MAX  _UI32_MAX\n#  endif // _WIN64 ]\n#endif // SIZE_MAX ]\n\n// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>\n#ifndef WCHAR_MIN // [\n#  define WCHAR_MIN  0\n#endif  // WCHAR_MIN ]\n#ifndef WCHAR_MAX // [\n#  define WCHAR_MAX  _UI16_MAX\n#endif  // WCHAR_MAX ]\n\n#define WINT_MIN  0\n#define WINT_MAX  _UI16_MAX\n\n#endif // __STDC_LIMIT_MACROS ]\n\n\n// 7.18.4 Limits of other integer types\n\n#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260\n\n// 7.18.4.1 Macros for minimum-width integer constants\n\n#define INT8_C(val)  val##i8\n#define INT16_C(val) val##i16\n#define INT32_C(val) val##i32\n#define INT64_C(val) val##i64\n\n#define UINT8_C(val)  val##ui8\n#define UINT16_C(val) val##ui16\n#define UINT32_C(val) val##ui32\n#define UINT64_C(val) val##ui64\n\n// 7.18.4.2 Macros for greatest-width integer constants\n// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.\n// Check out Issue 9 for the details.\n#ifndef INTMAX_C //   [\n#  define INTMAX_C   INT64_C\n#endif // INTMAX_C    ]\n#ifndef UINTMAX_C //  [\n#  define UINTMAX_C  UINT64_C\n#endif // UINTMAX_C   ]\n\n#endif // __STDC_CONSTANT_MACROS ]\n\n#endif // _MSC_VER >= 1600 ]\n\n#endif // _MSC_STDINT_H_ ]\n"
  },
  {
    "path": "src/thirdparty/rapidjson/ostreamwrapper.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_OSTREAMWRAPPER_H_\n#define RAPIDJSON_OSTREAMWRAPPER_H_\n\n#include \"stream.h\"\n#include <iosfwd>\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Wrapper of \\c std::basic_ostream into RapidJSON's Stream concept.\n/*!\n    The classes can be wrapped including but not limited to:\n\n    - \\c std::ostringstream\n    - \\c std::stringstream\n    - \\c std::wpstringstream\n    - \\c std::wstringstream\n    - \\c std::ifstream\n    - \\c std::fstream\n    - \\c std::wofstream\n    - \\c std::wfstream\n\n    \\tparam StreamType Class derived from \\c std::basic_ostream.\n*/\n   \ntemplate <typename StreamType>\nclass BasicOStreamWrapper {\npublic:\n    typedef typename StreamType::char_type Ch;\n    BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}\n\n    void Put(Ch c) {\n        stream_.put(c);\n    }\n\n    void Flush() {\n        stream_.flush();\n    }\n\n    // Not implemented\n    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }\n    char Take() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }\n    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }\n\nprivate:\n    BasicOStreamWrapper(const BasicOStreamWrapper&);\n    BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);\n\n    StreamType& stream_;\n};\n\ntypedef BasicOStreamWrapper<std::ostream> OStreamWrapper;\ntypedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_OSTREAMWRAPPER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/pointer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_POINTER_H_\n#define RAPIDJSON_POINTER_H_\n\n#include \"document.h\"\n#include \"internal/itoa.h\"\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(switch-enum)\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\nstatic const SizeType kPointerInvalidIndex = ~SizeType(0);  //!< Represents an invalid index in GenericPointer::Token\n\n//! Error code of parsing.\n/*! \\ingroup RAPIDJSON_ERRORS\n    \\see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode\n*/\nenum PointerParseErrorCode {\n    kPointerParseErrorNone = 0,                     //!< The parse is successful\n\n    kPointerParseErrorTokenMustBeginWithSolidus,    //!< A token must begin with a '/'\n    kPointerParseErrorInvalidEscape,                //!< Invalid escape\n    kPointerParseErrorInvalidPercentEncoding,       //!< Invalid percent encoding in URI fragment\n    kPointerParseErrorCharacterMustPercentEncode    //!< A character must percent encoded in URI fragment\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericPointer\n\n//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.\n/*!\n    This class implements RFC 6901 \"JavaScript Object Notation (JSON) Pointer\" \n    (https://tools.ietf.org/html/rfc6901).\n\n    A JSON pointer is for identifying a specific value in a JSON document\n    (GenericDocument). It can simplify coding of DOM tree manipulation, because it\n    can access multiple-level depth of DOM tree with single API call.\n\n    After it parses a string representation (e.g. \"/foo/0\" or URI fragment \n    representation (e.g. \"#/foo/0\") into its internal representation (tokens),\n    it can be used to resolve a specific value in multiple documents, or sub-tree \n    of documents.\n\n    Contrary to GenericValue, Pointer can be copy constructed and copy assigned.\n    Apart from assignment, a Pointer cannot be modified after construction.\n\n    Although Pointer is very convenient, please aware that constructing Pointer\n    involves parsing and dynamic memory allocation. A special constructor with user-\n    supplied tokens eliminates these.\n\n    GenericPointer depends on GenericDocument and GenericValue.\n    \n    \\tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >\n    \\tparam Allocator The allocator type for allocating memory for internal representation.\n    \n    \\note GenericPointer uses same encoding of ValueType.\n    However, Allocator of GenericPointer is independent of Allocator of Value.\n*/\ntemplate <typename ValueType, typename Allocator = CrtAllocator>\nclass GenericPointer {\npublic:\n    typedef typename ValueType::EncodingType EncodingType;  //!< Encoding type from Value\n    typedef typename ValueType::Ch Ch;                      //!< Character type from Value\n\n    //! A token is the basic units of internal representation.\n    /*!\n        A JSON pointer string representation \"/foo/123\" is parsed to two tokens: \n        \"foo\" and 123. 123 will be represented in both numeric form and string form.\n        They are resolved according to the actual value type (object or array).\n\n        For token that are not numbers, or the numeric value is out of bound\n        (greater than limits of SizeType), they are only treated as string form\n        (i.e. the token's index will be equal to kPointerInvalidIndex).\n\n        This struct is public so that user can create a Pointer without parsing and \n        allocation, using a special constructor.\n    */\n    struct Token {\n        const Ch* name;             //!< Name of the token. It has null character at the end but it can contain null character.\n        SizeType length;            //!< Length of the name.\n        SizeType index;             //!< A valid array index, if it is not equal to kPointerInvalidIndex.\n    };\n\n    //!@name Constructors and destructor.\n    //@{\n\n    //! Default constructor.\n    GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A null-terminated, string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n    */\n    explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, internal::StrLen(source));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Constructor that parses a string or URI fragment representation.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Requires the definition of the preprocessor symbol \\ref RAPIDJSON_HAS_STDSTRING.\n    */\n    explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source.c_str(), source.size());\n    }\n#endif\n\n    //! Constructor that parses a string or URI fragment representation, with length of the source string.\n    /*!\n        \\param source A string or URI fragment representation of JSON pointer.\n        \\param length Length of source.\n        \\param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.\n        \\note Slightly faster than the overload without length.\n    */\n    GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        Parse(source, length);\n    }\n\n    //! Constructor with user-supplied tokens.\n    /*!\n        This constructor let user supplies const array of tokens.\n        This prevents the parsing process and eliminates allocation.\n        This is preferred for memory constrained environments.\n\n        \\param tokens An constant array of tokens representing the JSON pointer.\n        \\param tokenCount Number of tokens.\n\n        \\b Example\n        \\code\n        #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }\n        #define INDEX(i) { #i, sizeof(#i) - 1, i }\n\n        static const Pointer::Token kTokens[] = { NAME(\"foo\"), INDEX(123) };\n        static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));\n        // Equivalent to static const Pointer p(\"/foo/123\");\n\n        #undef NAME\n        #undef INDEX\n        \\endcode\n    */\n    GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}\n\n    //! Copy constructor.\n    GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {\n        *this = rhs;\n    }\n\n    //! Destructor.\n    ~GenericPointer() {\n        if (nameBuffer_)    // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.\n            Allocator::Free(tokens_);\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    //! Assignment operator.\n    GenericPointer& operator=(const GenericPointer& rhs) {\n        if (this != &rhs) {\n            // Do not delete ownAllcator\n            if (nameBuffer_)\n                Allocator::Free(tokens_);\n\n            tokenCount_ = rhs.tokenCount_;\n            parseErrorOffset_ = rhs.parseErrorOffset_;\n            parseErrorCode_ = rhs.parseErrorCode_;\n\n            if (rhs.nameBuffer_)\n                CopyFromRaw(rhs); // Normally parsed tokens.\n            else {\n                tokens_ = rhs.tokens_; // User supplied const tokens.\n                nameBuffer_ = 0;\n            }\n        }\n        return *this;\n    }\n\n    //@}\n\n    //!@name Append token\n    //@{\n\n    //! Append a token and return a new Pointer\n    /*!\n        \\param token Token to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Token& token, Allocator* allocator = 0) const {\n        GenericPointer r;\n        r.allocator_ = allocator;\n        Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);\n        std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));\n        r.tokens_[tokenCount_].name = p;\n        r.tokens_[tokenCount_].length = token.length;\n        r.tokens_[tokenCount_].index = token.index;\n        return r;\n    }\n\n    //! Append a name token with length, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param length Length of name.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {\n        Token token = { name, length, kPointerInvalidIndex };\n        return Append(token, allocator);\n    }\n\n    //! Append a name token without length, and return a new Pointer\n    /*!\n        \\param name Name (const Ch*) to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))\n    Append(T* name, Allocator* allocator = 0) const {\n        return Append(name, StrLen(name), allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Append a name token, and return a new Pointer\n    /*!\n        \\param name Name to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {\n        return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);\n    }\n#endif\n\n    //! Append a index token, and return a new Pointer\n    /*!\n        \\param index Index to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(SizeType index, Allocator* allocator = 0) const {\n        char buffer[21];\n        char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);\n        SizeType length = static_cast<SizeType>(end - buffer);\n        buffer[length] = '\\0';\n\n        if (sizeof(Ch) == 1) {\n            Token token = { reinterpret_cast<Ch*>(buffer), length, index };\n            return Append(token, allocator);\n        }\n        else {\n            Ch name[21];\n            for (size_t i = 0; i <= length; i++)\n                name[i] = buffer[i];\n            Token token = { name, length, index };\n            return Append(token, allocator);\n        }\n    }\n\n    //! Append a token by value, and return a new Pointer\n    /*!\n        \\param token token to be appended.\n        \\param allocator Allocator for the newly return Pointer.\n        \\return A new Pointer with appended token.\n    */\n    GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {\n        if (token.IsString())\n            return Append(token.GetString(), token.GetStringLength(), allocator);\n        else {\n            RAPIDJSON_ASSERT(token.IsUint64());\n            RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));\n            return Append(static_cast<SizeType>(token.GetUint64()), allocator);\n        }\n    }\n\n    //!@name Handling Parse Error\n    //@{\n\n    //! Check whether this is a valid pointer.\n    bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }\n\n    //! Get the parsing error offset in code unit.\n    size_t GetParseErrorOffset() const { return parseErrorOffset_; }\n\n    //! Get the parsing error code.\n    PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }\n\n    //@}\n\n    //! Get the allocator of this pointer.\n    Allocator& GetAllocator() { return *allocator_; }\n\n    //!@name Tokens\n    //@{\n\n    //! Get the token array (const version only).\n    const Token* GetTokens() const { return tokens_; }\n\n    //! Get the number of tokens.\n    size_t GetTokenCount() const { return tokenCount_; }\n\n    //@}\n\n    //!@name Equality/inequality operators\n    //@{\n\n    //! Equality operator.\n    /*!\n        \\note When any pointers are invalid, always returns false.\n    */\n    bool operator==(const GenericPointer& rhs) const {\n        if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)\n            return false;\n\n        for (size_t i = 0; i < tokenCount_; i++) {\n            if (tokens_[i].index != rhs.tokens_[i].index ||\n                tokens_[i].length != rhs.tokens_[i].length || \n                (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))\n            {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    //! Inequality operator.\n    /*!\n        \\note When any pointers are invalid, always returns true.\n    */\n    bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }\n\n    //@}\n\n    //!@name Stringify\n    //@{\n\n    //! Stringify the pointer into string representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        return Stringify<false, OutputStream>(os);\n    }\n\n    //! Stringify the pointer into URI fragment representation.\n    /*!\n        \\tparam OutputStream Type of output stream.\n        \\param os The output stream.\n    */\n    template<typename OutputStream>\n    bool StringifyUriFragment(OutputStream& os) const {\n        return Stringify<true, OutputStream>(os);\n    }\n\n    //@}\n\n    //!@name Create value\n    //@{\n\n    //! Create a value in a subtree.\n    /*!\n        If the value is not exist, it creates all parent values and a JSON Null value.\n        So it always succeed and return the newly created or existing value.\n\n        Remind that it may change types of parents according to tokens, so it \n        potentially removes previously stored values. For example, if a document \n        was an array, and \"/foo\" is used to create a value, then the document \n        will be changed to an object, and all existing array elements are lost.\n\n        \\param root Root value of a DOM subtree to be resolved. It can be any value other than document root.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created (a JSON Null value), or already exists value.\n    */\n    ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        bool exist = true;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            if (v->IsArray() && t->name[0] == '-' && t->length == 1) {\n                v->PushBack(ValueType().Move(), allocator);\n                v = &((*v)[v->Size() - 1]);\n                exist = false;\n            }\n            else {\n                if (t->index == kPointerInvalidIndex) { // must be object name\n                    if (!v->IsObject())\n                        v->SetObject(); // Change to Object\n                }\n                else { // object name or array index\n                    if (!v->IsArray() && !v->IsObject())\n                        v->SetArray(); // Change to Array\n                }\n\n                if (v->IsArray()) {\n                    if (t->index >= v->Size()) {\n                        v->Reserve(t->index + 1, allocator);\n                        while (t->index >= v->Size())\n                            v->PushBack(ValueType().Move(), allocator);\n                        exist = false;\n                    }\n                    v = &((*v)[t->index]);\n                }\n                else {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd()) {\n                        v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);\n                        v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end\n                        exist = false;\n                    }\n                    else\n                        v = &m->value;\n                }\n            }\n        }\n\n        if (alreadyExist)\n            *alreadyExist = exist;\n\n        return *v;\n    }\n\n    //! Creates a value in a document.\n    /*!\n        \\param document A document to be resolved.\n        \\param alreadyExist If non-null, it stores whether the resolved value is already exist.\n        \\return The resolved newly created, or already exists value.\n    */\n    template <typename stackAllocator>\n    ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {\n        return Create(document, document.GetAllocator(), alreadyExist);\n    }\n\n    //@}\n\n    //!@name Query value\n    //@{\n\n    //! Query a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n\n        \\note\n        There are only 3 situations when a value cannot be resolved:\n        1. A value in the path is not an array nor object.\n        2. An object value does not contain the token.\n        3. A token is out of range of an array value.\n\n        Use unresolvedTokenIndex to retrieve the token index.\n    */\n    ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {\n        RAPIDJSON_ASSERT(IsValid());\n        ValueType* v = &root;\n        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        break;\n                    v = &m->value;\n                }\n                continue;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    break;\n                v = &((*v)[t->index]);\n                continue;\n            default:\n                break;\n            }\n\n            // Error: unresolved token\n            if (unresolvedTokenIndex)\n                *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);\n            return 0;\n        }\n        return v;\n    }\n\n    //! Query a const value in a const subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Pointer to the value if it can be resolved. Otherwise null.\n    */\n    const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { \n        return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);\n    }\n\n    //@}\n\n    //!@name Query a value with default\n    //@{\n\n    //! Query a value in a subtree with default value.\n    /*!\n        Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.\n        So that this function always succeed.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param defaultValue Default value to be cloned if the value was not exists.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);\n    }\n\n    //! Query a value in a subtree with default null-terminated string.\n    ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a subtree with default std::basic_string.\n    ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {\n        bool alreadyExist;\n        Value& v = Create(root, allocator, &alreadyExist);\n        return alreadyExist ? v : v.SetString(defaultValue, allocator);\n    }\n#endif\n\n    //! Query a value in a subtree with default primitive value.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {\n        return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);\n    }\n\n    //! Query a value in a document with default value.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //! Query a value in a document with default null-terminated string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n    \n#if RAPIDJSON_HAS_STDSTRING\n    //! Query a value in a document with default std::basic_string.\n    template <typename stackAllocator>\n    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n#endif\n\n    //! Query a value in a document with default primitive value.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {\n        return GetWithDefault(document, defaultValue, document.GetAllocator());\n    }\n\n    //@}\n\n    //!@name Set a value\n    //@{\n\n    //! Set a value in a subtree, with move semantics.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be set.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = value;\n    }\n\n    //! Set a value in a subtree, with copy semantics.\n    ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).CopyFrom(value, allocator);\n    }\n\n    //! Set a null-terminated string in a subtree.\n    ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Set a std::basic_string in a subtree.\n    ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value, allocator).Move();\n    }\n#endif\n\n    //! Set a primitive value in a subtree.\n    /*!\n        \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n    Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator) = ValueType(value).Move();\n    }\n\n    //! Set a value in a document, with move semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document) = value;\n    }\n\n    //! Set a value in a document, with copy semantics.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {\n        return Create(document).CopyFrom(value, document.GetAllocator());\n    }\n\n    //! Set a null-terminated string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    //! Sets a std::basic_string in a document.\n    template <typename stackAllocator>\n    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {\n        return Create(document) = ValueType(value, document.GetAllocator()).Move();\n    }\n#endif\n\n    //! Set a primitive value in a document.\n    /*!\n    \\tparam T Either \\ref Type, \\c int, \\c unsigned, \\c int64_t, \\c uint64_t, \\c bool\n    */\n    template <typename T, typename stackAllocator>\n    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))\n        Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {\n            return Create(document) = value;\n    }\n\n    //@}\n\n    //!@name Swap a value\n    //@{\n\n    //! Swap a value with a value in a subtree.\n    /*!\n        It creates all parents if they are not exist or types are different to the tokens.\n        So this function always succeeds but potentially remove existing values.\n\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\param value Value to be swapped.\n        \\param allocator Allocator for creating the values if the specified value or its parents are not exist.\n        \\see Create()\n    */\n    ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {\n        return Create(root, allocator).Swap(value);\n    }\n\n    //! Swap a value with a value in a document.\n    template <typename stackAllocator>\n    ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {\n        return Create(document).Swap(value);\n    }\n\n    //@}\n\n    //! Erase a value in a subtree.\n    /*!\n        \\param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.\n        \\return Whether the resolved value is found and erased.\n\n        \\note Erasing with an empty pointer \\c Pointer(\"\"), i.e. the root, always fail and return false.\n    */\n    bool Erase(ValueType& root) const {\n        RAPIDJSON_ASSERT(IsValid());\n        if (tokenCount_ == 0) // Cannot erase the root\n            return false;\n\n        ValueType* v = &root;\n        const Token* last = tokens_ + (tokenCount_ - 1);\n        for (const Token *t = tokens_; t != last; ++t) {\n            switch (v->GetType()) {\n            case kObjectType:\n                {\n                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));\n                    if (m == v->MemberEnd())\n                        return false;\n                    v = &m->value;\n                }\n                break;\n            case kArrayType:\n                if (t->index == kPointerInvalidIndex || t->index >= v->Size())\n                    return false;\n                v = &((*v)[t->index]);\n                break;\n            default:\n                return false;\n            }\n        }\n\n        switch (v->GetType()) {\n        case kObjectType:\n            return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));\n        case kArrayType:\n            if (last->index == kPointerInvalidIndex || last->index >= v->Size())\n                return false;\n            v->Erase(v->Begin() + last->index);\n            return true;\n        default:\n            return false;\n        }\n    }\n\nprivate:\n    //! Clone the content from rhs to this.\n    /*!\n        \\param rhs Source pointer.\n        \\param extraToken Extra tokens to be allocated.\n        \\param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.\n        \\return Start of non-occupied name buffer, for storing extra names.\n    */\n    Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {\n        if (!allocator_) // allocator is independently owned.\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n\n        size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens\n        for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)\n            nameBufferSize += t->length;\n\n        tokenCount_ = rhs.tokenCount_ + extraToken;\n        tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));\n        nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        if (rhs.tokenCount_ > 0) {\n            std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));\n        }\n        if (nameBufferSize > 0) {\n            std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));\n        }\n\n        // Adjust pointers to name buffer\n        std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;\n        for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)\n            t->name += diff;\n\n        return nameBuffer_ + nameBufferSize;\n    }\n\n    //! Check whether a character should be percent-encoded.\n    /*!\n        According to RFC 3986 2.3 Unreserved Characters.\n        \\param c The character (code unit) to be tested.\n    */\n    bool NeedPercentEncode(Ch c) const {\n        return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');\n    }\n\n    //! Parse a JSON String or its URI fragment representation into tokens.\n#ifndef __clang__ // -Wdocumentation\n    /*!\n        \\param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.\n        \\param length Length of the source string.\n        \\note Source cannot be JSON String Representation of JSON Pointer, e.g. In \"/\\u0000\", \\u0000 will not be unescaped.\n    */\n#endif\n    void Parse(const Ch* source, size_t length) {\n        RAPIDJSON_ASSERT(source != NULL);\n        RAPIDJSON_ASSERT(nameBuffer_ == 0);\n        RAPIDJSON_ASSERT(tokens_ == 0);\n\n        // Create own allocator if user did not supply.\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n\n        // Count number of '/' as tokenCount\n        tokenCount_ = 0;\n        for (const Ch* s = source; s != source + length; s++) \n            if (*s == '/')\n                tokenCount_++;\n\n        Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));\n        Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);\n        size_t i = 0;\n\n        // Detect if it is a URI fragment\n        bool uriFragment = false;\n        if (source[i] == '#') {\n            uriFragment = true;\n            i++;\n        }\n\n        if (i != length && source[i] != '/') {\n            parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;\n            goto error;\n        }\n\n        while (i < length) {\n            RAPIDJSON_ASSERT(source[i] == '/');\n            i++; // consumes '/'\n\n            token->name = name;\n            bool isNumber = true;\n\n            while (i < length && source[i] != '/') {\n                Ch c = source[i];\n                if (uriFragment) {\n                    // Decoding percent-encoding for URI fragment\n                    if (c == '%') {\n                        PercentDecodeStream is(&source[i], source + length);\n                        GenericInsituStringStream<EncodingType> os(name);\n                        Ch* begin = os.PutBegin();\n                        if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {\n                            parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;\n                            goto error;\n                        }\n                        size_t len = os.PutEnd(begin);\n                        i += is.Tell() - 1;\n                        if (len == 1)\n                            c = *name;\n                        else {\n                            name += len;\n                            isNumber = false;\n                            i++;\n                            continue;\n                        }\n                    }\n                    else if (NeedPercentEncode(c)) {\n                        parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;\n                        goto error;\n                    }\n                }\n\n                i++;\n                \n                // Escaping \"~0\" -> '~', \"~1\" -> '/'\n                if (c == '~') {\n                    if (i < length) {\n                        c = source[i];\n                        if (c == '0')       c = '~';\n                        else if (c == '1')  c = '/';\n                        else {\n                            parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                            goto error;\n                        }\n                        i++;\n                    }\n                    else {\n                        parseErrorCode_ = kPointerParseErrorInvalidEscape;\n                        goto error;\n                    }\n                }\n\n                // First check for index: all of characters are digit\n                if (c < '0' || c > '9')\n                    isNumber = false;\n\n                *name++ = c;\n            }\n            token->length = static_cast<SizeType>(name - token->name);\n            if (token->length == 0)\n                isNumber = false;\n            *name++ = '\\0'; // Null terminator\n\n            // Second check for index: more than one digit cannot have leading zero\n            if (isNumber && token->length > 1 && token->name[0] == '0')\n                isNumber = false;\n\n            // String to SizeType conversion\n            SizeType n = 0;\n            if (isNumber) {\n                for (size_t j = 0; j < token->length; j++) {\n                    SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');\n                    if (m < n) {   // overflow detection\n                        isNumber = false;\n                        break;\n                    }\n                    n = m;\n                }\n            }\n\n            token->index = isNumber ? n : kPointerInvalidIndex;\n            token++;\n        }\n\n        RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer\n        parseErrorCode_ = kPointerParseErrorNone;\n        return;\n\n    error:\n        Allocator::Free(tokens_);\n        nameBuffer_ = 0;\n        tokens_ = 0;\n        tokenCount_ = 0;\n        parseErrorOffset_ = i;\n        return;\n    }\n\n    //! Stringify to string or URI fragment representation.\n    /*!\n        \\tparam uriFragment True for stringifying to URI fragment representation. False for string representation.\n        \\tparam OutputStream type of output stream.\n        \\param os The output stream.\n    */\n    template<bool uriFragment, typename OutputStream>\n    bool Stringify(OutputStream& os) const {\n        RAPIDJSON_ASSERT(IsValid());\n\n        if (uriFragment)\n            os.Put('#');\n\n        for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {\n            os.Put('/');\n            for (size_t j = 0; j < t->length; j++) {\n                Ch c = t->name[j];\n                if (c == '~') {\n                    os.Put('~');\n                    os.Put('0');\n                }\n                else if (c == '/') {\n                    os.Put('~');\n                    os.Put('1');\n                }\n                else if (uriFragment && NeedPercentEncode(c)) { \n                    // Transcode to UTF8 sequence\n                    GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);\n                    PercentEncodeStream<OutputStream> target(os);\n                    if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))\n                        return false;\n                    j += source.Tell() - 1;\n                }\n                else\n                    os.Put(c);\n            }\n        }\n        return true;\n    }\n\n    //! A helper stream for decoding a percent-encoded sequence into code unit.\n    /*!\n        This stream decodes %XY triplet into code unit (0-255).\n        If it encounters invalid characters, it sets output code unit as 0 and \n        mark invalid, and to be checked by IsValid().\n    */\n    class PercentDecodeStream {\n    public:\n        typedef typename ValueType::Ch Ch;\n\n        //! Constructor\n        /*!\n            \\param source Start of the stream\n            \\param end Past-the-end of the stream.\n        */\n        PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}\n\n        Ch Take() {\n            if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet\n                valid_ = false;\n                return 0;\n            }\n            src_++;\n            Ch c = 0;\n            for (int j = 0; j < 2; j++) {\n                c = static_cast<Ch>(c << 4);\n                Ch h = *src_;\n                if      (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');\n                else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);\n                else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);\n                else {\n                    valid_ = false;\n                    return 0;\n                }\n                src_++;\n            }\n            return c;\n        }\n\n        size_t Tell() const { return static_cast<size_t>(src_ - head_); }\n        bool IsValid() const { return valid_; }\n\n    private:\n        const Ch* src_;     //!< Current read position.\n        const Ch* head_;    //!< Original head of the string.\n        const Ch* end_;     //!< Past-the-end position.\n        bool valid_;        //!< Whether the parsing is valid.\n    };\n\n    //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.\n    template <typename OutputStream>\n    class PercentEncodeStream {\n    public:\n        PercentEncodeStream(OutputStream& os) : os_(os) {}\n        void Put(char c) { // UTF-8 must be byte\n            unsigned char u = static_cast<unsigned char>(c);\n            static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n            os_.Put('%');\n            os_.Put(hexDigits[u >> 4]);\n            os_.Put(hexDigits[u & 15]);\n        }\n    private:\n        OutputStream& os_;\n    };\n\n    Allocator* allocator_;                  //!< The current allocator. It is either user-supplied or equal to ownAllocator_.\n    Allocator* ownAllocator_;               //!< Allocator owned by this Pointer.\n    Ch* nameBuffer_;                        //!< A buffer containing all names in tokens.\n    Token* tokens_;                         //!< A list of tokens.\n    size_t tokenCount_;                     //!< Number of tokens in tokens_.\n    size_t parseErrorOffset_;               //!< Offset in code unit when parsing fail.\n    PointerParseErrorCode parseErrorCode_;  //!< Parsing error code.\n};\n\n//! GenericPointer for Value (UTF-8, default allocator).\ntypedef GenericPointer<Value> Pointer;\n\n//!@name Helper functions for GenericPointer\n//@{\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {\n    return pointer.Create(root, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {\n    return pointer.Create(document);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {\n    return pointer.Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T>\nconst typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {\n    return pointer.Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nconst typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {\n    return pointer.GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nGetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {\n    return pointer.GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nGetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T>\ntypename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {\n    return pointer.Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n#endif\n\ntemplate <typename T, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))\nSetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);\n}\n\n// No allocator parameter\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {\n    return pointer.Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {\n    return pointer.Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {\n    return pointer.Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n#if RAPIDJSON_HAS_STDSTRING\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n#endif\n\ntemplate <typename DocumentType, typename CharType, size_t N, typename T2>\nRAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))\nSetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\ntypename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {\n    return pointer.Swap(root, value, a);\n}\n\ntemplate <typename T, typename CharType, size_t N>\ntypename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);\n}\n\ntemplate <typename DocumentType>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {\n    return pointer.Swap(document, value);\n}\n\ntemplate <typename DocumentType, typename CharType, size_t N>\ntypename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {\n    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);\n}\n\n//////////////////////////////////////////////////////////////////////////////\n\ntemplate <typename T>\nbool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {\n    return pointer.Erase(root);\n}\n\ntemplate <typename T, typename CharType, size_t N>\nbool EraseValueByPointer(T& root, const CharType(&source)[N]) {\n    return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);\n}\n\n//@}\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_POINTER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/prettywriter.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_PRETTYWRITER_H_\n#define RAPIDJSON_PRETTYWRITER_H_\n\n#include \"writer.h\"\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Combination of PrettyWriter format flags.\n/*! \\see PrettyWriter::SetFormatOptions\n */\nenum PrettyFormatOptions {\n    kFormatDefault = 0,         //!< Default pretty formatting.\n    kFormatSingleLineArray = 1  //!< Format arrays on a single line.\n};\n\n//! Writer with indentation and spacing.\n/*!\n    \\tparam OutputStream Type of ouptut os.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>\nclass PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {\npublic:\n    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;\n    typedef typename Base::Ch Ch;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param allocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}\n\n\n    explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : \n        Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}\n\n    //! Set custom indentation.\n    /*! \\param indentChar       Character for indentation. Must be whitespace character (' ', '\\\\t', '\\\\n', '\\\\r').\n        \\param indentCharCount  Number of indent characters for each indentation level.\n        \\note The default indentation is 4 spaces.\n    */\n    PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {\n        RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\\t' || indentChar == '\\n' || indentChar == '\\r');\n        indentChar_ = indentChar;\n        indentCharCount_ = indentCharCount;\n        return *this;\n    }\n\n    //! Set pretty writer formatting options.\n    /*! \\param options Formatting options.\n    */\n    PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {\n        formatOptions_ = options;\n        return *this;\n    }\n\n    /*! @name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { PrettyPrefix(kNullType);   return Base::WriteNull(); }\n    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }\n    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::WriteInt(i); }\n    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::WriteUint(u); }\n    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }\n    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::WriteUint64(u64);  }\n    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        PrettyPrefix(kNumberType);\n        return Base::WriteString(str, length);\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        PrettyPrefix(kStringType);\n        return Base::WriteString(str, length);\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        PrettyPrefix(kObjectType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);\n        return Base::WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool Key(const std::basic_string<Ch>& str) {\n        return Key(str.data(), SizeType(str.size()));\n    }\n#endif\n\t\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);\n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::WriteEndObject();\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::os_->Flush();\n        return true;\n    }\n\n    bool StartArray() {\n        PrettyPrefix(kArrayType);\n        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);\n        return Base::WriteStartArray();\n    }\n\n    bool EndArray(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));\n        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);\n        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;\n\n        if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {\n            Base::os_->Put('\\n');\n            WriteIndent();\n        }\n        bool ret = Base::WriteEndArray();\n        (void)ret;\n        RAPIDJSON_ASSERT(ret == true);\n        if (Base::level_stack_.Empty()) // end of json text\n            Base::os_->Flush();\n        return true;\n    }\n\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }\n\n    //@}\n\n    //! Write a raw JSON value.\n    /*!\n        For user to write a stringified JSON as a value.\n\n        \\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.\n        \\param length Length of the json.\n        \\param type Type of the root of json.\n        \\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.\n    */\n    bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }\n\nprotected:\n    void PrettyPrefix(Type type) {\n        (void)type;\n        if (Base::level_stack_.GetSize() != 0) { // this value is not at root\n            typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();\n\n            if (level->inArray) {\n                if (level->valueCount > 0) {\n                    Base::os_->Put(','); // add comma if it is not the first element in array\n                    if (formatOptions_ & kFormatSingleLineArray)\n                        Base::os_->Put(' ');\n                }\n\n                if (!(formatOptions_ & kFormatSingleLineArray)) {\n                    Base::os_->Put('\\n');\n                    WriteIndent();\n                }\n            }\n            else {  // in object\n                if (level->valueCount > 0) {\n                    if (level->valueCount % 2 == 0) {\n                        Base::os_->Put(',');\n                        Base::os_->Put('\\n');\n                    }\n                    else {\n                        Base::os_->Put(':');\n                        Base::os_->Put(' ');\n                    }\n                }\n                else\n                    Base::os_->Put('\\n');\n\n                if (level->valueCount % 2 == 0)\n                    WriteIndent();\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.\n            Base::hasRoot_ = true;\n        }\n    }\n\n    void WriteIndent()  {\n        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;\n        PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);\n    }\n\n    Ch indentChar_;\n    unsigned indentCharCount_;\n    PrettyFormatOptions formatOptions_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    PrettyWriter(const PrettyWriter&);\n    PrettyWriter& operator=(const PrettyWriter&);\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/rapidjson.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_RAPIDJSON_H_\n#define RAPIDJSON_RAPIDJSON_H_\n\n/*!\\file rapidjson.h\n    \\brief common definitions and configuration\n    \n    \\see RAPIDJSON_CONFIG\n */\n\n/*! \\defgroup RAPIDJSON_CONFIG RapidJSON configuration\n    \\brief Configuration macros for library features\n\n    Some RapidJSON features are configurable to adapt the library to a wide\n    variety of platforms, environments and usage scenarios.  Most of the\n    features can be configured in terms of overriden or predefined\n    preprocessor macros at compile-time.\n\n    Some additional customization is available in the \\ref RAPIDJSON_ERRORS APIs.\n\n    \\note These macros should be given on the compiler command-line\n          (where applicable)  to avoid inconsistent values when compiling\n          different translation units of a single application.\n */\n\n#include <cstdlib>  // malloc(), realloc(), free(), size_t\n#include <cstring>  // memset(), memcpy(), memmove(), memcmp()\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_VERSION_STRING\n//\n// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.\n//\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n// token stringification\n#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)\n#define RAPIDJSON_DO_STRINGIFY(x) #x\n//!@endcond\n\n/*! \\def RAPIDJSON_MAJOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Major version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_MINOR_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Minor version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_PATCH_VERSION\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Patch version of RapidJSON in integer.\n*/\n/*! \\def RAPIDJSON_VERSION_STRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Version of RapidJSON in \"<major>.<minor>.<patch>\" string format.\n*/\n#define RAPIDJSON_MAJOR_VERSION 1\n#define RAPIDJSON_MINOR_VERSION 1\n#define RAPIDJSON_PATCH_VERSION 0\n#define RAPIDJSON_VERSION_STRING \\\n    RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NAMESPACE_(BEGIN|END)\n/*! \\def RAPIDJSON_NAMESPACE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace\n\n    In order to avoid symbol clashes and/or \"One Definition Rule\" errors\n    between multiple inclusions of (different versions of) RapidJSON in\n    a single binary, users can customize the name of the main RapidJSON\n    namespace.\n\n    In case of a single nesting level, defining \\c RAPIDJSON_NAMESPACE\n    to a custom name (e.g. \\c MyRapidJSON) is sufficient.  If multiple\n    levels are needed, both \\ref RAPIDJSON_NAMESPACE_BEGIN and \\ref\n    RAPIDJSON_NAMESPACE_END need to be defined as well:\n\n    \\code\n    // in some .cpp file\n    #define RAPIDJSON_NAMESPACE my::rapidjson\n    #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {\n    #define RAPIDJSON_NAMESPACE_END   } }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson\n */\n/*! \\def RAPIDJSON_NAMESPACE_BEGIN\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (opening expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n/*! \\def RAPIDJSON_NAMESPACE_END\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief   provide custom rapidjson namespace (closing expression)\n    \\see RAPIDJSON_NAMESPACE\n*/\n#ifndef RAPIDJSON_NAMESPACE\n#define RAPIDJSON_NAMESPACE rapidjson\n#endif\n#ifndef RAPIDJSON_NAMESPACE_BEGIN\n#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {\n#endif\n#ifndef RAPIDJSON_NAMESPACE_END\n#define RAPIDJSON_NAMESPACE_END }\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_HAS_STDSTRING\n\n#ifndef RAPIDJSON_HAS_STDSTRING\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation\n#else\n#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default\n#endif\n/*! \\def RAPIDJSON_HAS_STDSTRING\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable RapidJSON support for \\c std::string\n\n    By defining this preprocessor symbol to \\c 1, several convenience functions for using\n    \\ref rapidjson::GenericValue with \\c std::string are enabled, especially\n    for construction and comparison.\n\n    \\hideinitializer\n*/\n#endif // !defined(RAPIDJSON_HAS_STDSTRING)\n\n#if RAPIDJSON_HAS_STDSTRING\n#include <string>\n#endif // RAPIDJSON_HAS_STDSTRING\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_INT64DEFINE\n\n/*! \\def RAPIDJSON_NO_INT64DEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Use external 64-bit integer types.\n\n    RapidJSON requires the 64-bit integer types \\c int64_t and  \\c uint64_t types\n    to be available at global scope.\n\n    If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to\n    prevent RapidJSON from defining its own types.\n*/\n#ifndef RAPIDJSON_NO_INT64DEFINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#if defined(_MSC_VER) && (_MSC_VER < 1800)\t// Visual Studio 2013\n#include \"msinttypes/stdint.h\"\n#include \"msinttypes/inttypes.h\"\n#else\n// Other compilers should have this.\n#include <stdint.h>\n#include <inttypes.h>\n#endif\n//!@endcond\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_INT64DEFINE\n#endif\n#endif // RAPIDJSON_NO_INT64TYPEDEF\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_FORCEINLINE\n\n#ifndef RAPIDJSON_FORCEINLINE\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#if defined(_MSC_VER) && defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __forceinline\n#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)\n#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))\n#else\n#define RAPIDJSON_FORCEINLINE\n#endif\n//!@endcond\n#endif // RAPIDJSON_FORCEINLINE\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ENDIAN\n#define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine\n#define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine\n\n//! Endianness of the machine.\n/*!\n    \\def RAPIDJSON_ENDIAN\n    \\ingroup RAPIDJSON_CONFIG\n\n    GCC 4.6 provided macro for detecting endianness of the target machine. But other\n    compilers may not have this. User can define RAPIDJSON_ENDIAN to either\n    \\ref RAPIDJSON_LITTLEENDIAN or \\ref RAPIDJSON_BIGENDIAN.\n\n    Default detection implemented with reference to\n    \\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html\n    \\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp\n*/\n#ifndef RAPIDJSON_ENDIAN\n// Detect with GCC 4.6's macro\n#  ifdef __BYTE_ORDER__\n#    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.\n#    endif // __BYTE_ORDER__\n// Detect with GLIBC's endian.h\n#  elif defined(__GLIBC__)\n#    include <endian.h>\n#    if (__BYTE_ORDER == __LITTLE_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#    elif (__BYTE_ORDER == __BIG_ENDIAN)\n#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#    else\n#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.\n#   endif // __GLIBC__\n// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro\n#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n// Detect with architecture macros\n#  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN\n#  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(_MSC_VER) && defined(_M_ARM)\n#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN\n#  elif defined(RAPIDJSON_DOXYGEN_RUNNING)\n#    define RAPIDJSON_ENDIAN\n#  else\n#    error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.   \n#  endif\n#endif // RAPIDJSON_ENDIAN\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_64BIT\n\n//! Whether using 64-bit architecture\n#ifndef RAPIDJSON_64BIT\n#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)\n#define RAPIDJSON_64BIT 1\n#else\n#define RAPIDJSON_64BIT 0\n#endif\n#endif // RAPIDJSON_64BIT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ALIGN\n\n//! Data alignment of the machine.\n/*! \\ingroup RAPIDJSON_CONFIG\n    \\param x pointer to align\n\n    Some machines require strict data alignment. Currently the default uses 4 bytes\n    alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.\n    User can customize by defining the RAPIDJSON_ALIGN function macro.\n*/\n#ifndef RAPIDJSON_ALIGN\n#if RAPIDJSON_64BIT == 1\n#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))\n#else\n#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)\n#endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_UINT64_C2\n\n//! Construct a 64-bit literal by a pair of 32-bit integer.\n/*!\n    64-bit literal with or without ULL suffix is prone to compiler warnings.\n    UINT64_C() is C macro which cause compilation problems.\n    Use this macro to define 64-bit constants by a pair of 32-bit integer.\n*/\n#ifndef RAPIDJSON_UINT64_C2\n#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n//! Use only lower 48-bit address for some pointers.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n\n    This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.\n    The higher 16-bit can be used for storing other data.\n    \\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.\n*/\n#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION\n#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)\n#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1\n#else\n#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0\n#endif\n#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION\n\n#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1\n#if RAPIDJSON_64BIT != 1\n#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1\n#endif\n#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))\n#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))\n#else\n#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))\n#define RAPIDJSON_GETPOINTER(type, p) (p)\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD\n\n/*! \\def RAPIDJSON_SIMD\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief Enable SSE2/SSE4.2 optimization.\n\n    RapidJSON supports optimized implementations for some parsing operations\n    based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible\n    processors.\n\n    To enable these optimizations, two different symbols can be defined;\n    \\code\n    // Enable SSE2 optimization.\n    #define RAPIDJSON_SSE2\n\n    // Enable SSE4.2 optimization.\n    #define RAPIDJSON_SSE42\n    \\endcode\n\n    \\c RAPIDJSON_SSE42 takes precedence, if both are defined.\n\n    If any of these symbols is defined, RapidJSON defines the macro\n    \\c RAPIDJSON_SIMD to indicate the availability of the optimized code.\n*/\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \\\n    || defined(RAPIDJSON_DOXYGEN_RUNNING)\n#define RAPIDJSON_SIMD\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_NO_SIZETYPEDEFINE\n\n#ifndef RAPIDJSON_NO_SIZETYPEDEFINE\n/*! \\def RAPIDJSON_NO_SIZETYPEDEFINE\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-provided \\c SizeType definition.\n\n    In order to avoid using 32-bit size types for indexing strings and arrays,\n    define this preprocessor symbol and provide the type rapidjson::SizeType\n    before including RapidJSON:\n    \\code\n    #define RAPIDJSON_NO_SIZETYPEDEFINE\n    namespace rapidjson { typedef ::std::size_t SizeType; }\n    #include \"rapidjson/...\"\n    \\endcode\n\n    \\see rapidjson::SizeType\n*/\n#ifdef RAPIDJSON_DOXYGEN_RUNNING\n#define RAPIDJSON_NO_SIZETYPEDEFINE\n#endif\nRAPIDJSON_NAMESPACE_BEGIN\n//! Size type (for string lengths, array sizes, etc.)\n/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,\n    instead of using \\c size_t. Users may override the SizeType by defining\n    \\ref RAPIDJSON_NO_SIZETYPEDEFINE.\n*/\ntypedef unsigned SizeType;\nRAPIDJSON_NAMESPACE_END\n#endif\n\n// always import std::size_t to rapidjson namespace\nRAPIDJSON_NAMESPACE_BEGIN\nusing std::size_t;\nRAPIDJSON_NAMESPACE_END\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_ASSERT\n\n//! Assertion.\n/*! \\ingroup RAPIDJSON_CONFIG\n    By default, rapidjson uses C \\c assert() for internal assertions.\n    User can override it by defining RAPIDJSON_ASSERT(x) macro.\n\n    \\note Parsing errors are handled and can be customized by the\n          \\ref RAPIDJSON_ERRORS APIs.\n*/\n#ifndef RAPIDJSON_ASSERT\n#include <cassert>\n#define RAPIDJSON_ASSERT(x) assert(x)\n#endif // RAPIDJSON_ASSERT\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_STATIC_ASSERT\n\n// Adopt from boost\n#ifndef RAPIDJSON_STATIC_ASSERT\n#ifndef __clang__\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#endif\nRAPIDJSON_NAMESPACE_BEGIN\ntemplate <bool x> struct STATIC_ASSERTION_FAILURE;\ntemplate <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };\ntemplate<int x> struct StaticAssertTest {};\nRAPIDJSON_NAMESPACE_END\n\n#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)\n#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)\n#define RAPIDJSON_DO_JOIN2(X, Y) X##Y\n\n#if defined(__GNUC__)\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))\n#else\n#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE \n#endif\n#ifndef __clang__\n//!@endcond\n#endif\n\n/*! \\def RAPIDJSON_STATIC_ASSERT\n    \\brief (Internal) macro to check for conditions at compile-time\n    \\param x compile-time condition\n    \\hideinitializer\n */\n#define RAPIDJSON_STATIC_ASSERT(x) \\\n    typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \\\n      sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \\\n    RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY\n\n//! Compiler branching hint for expression with high probability to be true.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n    \\param x Boolean expression likely to be true.\n*/\n#ifndef RAPIDJSON_LIKELY\n#if defined(__GNUC__) || defined(__clang__)\n#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)\n#else\n#define RAPIDJSON_LIKELY(x) (x)\n#endif\n#endif\n\n//! Compiler branching hint for expression with low probability to be true.\n/*!\n    \\ingroup RAPIDJSON_CONFIG\n    \\param x Boolean expression unlikely to be true.\n*/\n#ifndef RAPIDJSON_UNLIKELY\n#if defined(__GNUC__) || defined(__clang__)\n#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)\n#else\n#define RAPIDJSON_UNLIKELY(x) (x)\n#endif\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Helpers\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n\n#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  \n#define RAPIDJSON_MULTILINEMACRO_END \\\n} while((void)0, 0)\n\n// adopted from Boost\n#define RAPIDJSON_VERSION_CODE(x,y,z) \\\n  (((x)*100000) + ((y)*100) + (z))\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF\n\n#if defined(__GNUC__)\n#define RAPIDJSON_GNUC \\\n    RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)\n#endif\n\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))\n\n#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)\n#define RAPIDJSON_DIAG_OFF(x) \\\n    RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))\n\n// push/pop support in Clang and GCC>=4.6\n#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n#else // GCC >= 4.2, < 4.6\n#define RAPIDJSON_DIAG_PUSH /* ignored */\n#define RAPIDJSON_DIAG_POP /* ignored */\n#endif\n\n#elif defined(_MSC_VER)\n\n// pragma (MSVC specific)\n#define RAPIDJSON_PRAGMA(x) __pragma(x)\n#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))\n\n#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)\n#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)\n#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)\n\n#else\n\n#define RAPIDJSON_DIAG_OFF(x) /* ignored */\n#define RAPIDJSON_DIAG_PUSH   /* ignored */\n#define RAPIDJSON_DIAG_POP    /* ignored */\n\n#endif // RAPIDJSON_DIAG_*\n\n///////////////////////////////////////////////////////////////////////////////\n// C++11 features\n\n#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#if defined(__clang__)\n#if __has_feature(cxx_rvalue_references) && \\\n    (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1\n#else\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0\n#endif\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n      (defined(_MSC_VER) && _MSC_VER >= 1600)\n\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1\n#else\n#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0\n#endif\n#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS\n\n#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))\n//    (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1\n#else\n#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0\n#endif\n#endif\n#if RAPIDJSON_HAS_CXX11_NOEXCEPT\n#define RAPIDJSON_NOEXCEPT noexcept\n#else\n#define RAPIDJSON_NOEXCEPT /* noexcept */\n#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT\n\n// no automatic detection, yet\n#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS\n#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0\n#endif\n\n#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR\n#if defined(__clang__)\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)\n#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \\\n      (defined(_MSC_VER) && _MSC_VER >= 1700)\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1\n#else\n#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0\n#endif\n#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR\n\n//!@endcond\n\n///////////////////////////////////////////////////////////////////////////////\n// new/delete\n\n#ifndef RAPIDJSON_NEW\n///! customization point for global \\c new\n#define RAPIDJSON_NEW(x) new x\n#endif\n#ifndef RAPIDJSON_DELETE\n///! customization point for global \\c delete\n#define RAPIDJSON_DELETE(x) delete x\n#endif\n\n///////////////////////////////////////////////////////////////////////////////\n// Type\n\n/*! \\namespace rapidjson\n    \\brief main RapidJSON namespace\n    \\see RAPIDJSON_NAMESPACE\n*/\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Type of JSON value\nenum Type {\n    kNullType = 0,      //!< null\n    kFalseType = 1,     //!< false\n    kTrueType = 2,      //!< true\n    kObjectType = 3,    //!< object\n    kArrayType = 4,     //!< array \n    kStringType = 5,    //!< string\n    kNumberType = 6     //!< number\n};\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/reader.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n//\n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed\n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR\n// CONDITIONS OF ANY KIND, either express or implied. See the License for the\n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_READER_H_\n#define RAPIDJSON_READER_H_\n\n/*! \\file reader.h */\n\n#include \"allocators.h\"\n#include \"stream.h\"\n#include \"encodedstream.h\"\n#include \"internal/meta.h\"\n#include \"internal/stack.h\"\n#include \"internal/strtod.h\"\n#include <limits>\n\n#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanForward)\n#endif\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127)  // conditional expression is constant\nRAPIDJSON_DIAG_OFF(4702)  // unreachable code\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(old-style-cast)\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(switch-enum)\n#endif\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define RAPIDJSON_NOTHING /* deliberately empty */\n#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)\n//!@endcond\n\n/*! \\def RAPIDJSON_PARSE_ERROR_NORETURN\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief Macro to indicate a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    This macros can be used as a customization point for the internal\n    error handling mechanism of RapidJSON.\n\n    A common usage model is to throw an exception instead of requiring the\n    caller to explicitly check the \\ref rapidjson::GenericReader::Parse's\n    return value:\n\n    \\code\n    #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \\\n       throw ParseException(parseErrorCode, #parseErrorCode, offset)\n\n    #include <stdexcept>               // std::runtime_error\n    #include \"rapidjson/error/error.h\" // rapidjson::ParseResult\n\n    struct ParseException : std::runtime_error, rapidjson::ParseResult {\n      ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)\n        : std::runtime_error(msg), ParseResult(code, offset) {}\n    };\n\n    #include \"rapidjson/reader.h\"\n    \\endcode\n\n    \\see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse\n */\n#ifndef RAPIDJSON_PARSE_ERROR_NORETURN\n#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \\\n    SetParseError(parseErrorCode, offset); \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n/*! \\def RAPIDJSON_PARSE_ERROR\n    \\ingroup RAPIDJSON_ERRORS\n    \\brief (Internal) macro to indicate and handle a parse error.\n    \\param parseErrorCode \\ref rapidjson::ParseErrorCode of the error\n    \\param offset  position of the error in JSON input (\\c size_t)\n\n    Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.\n\n    \\see RAPIDJSON_PARSE_ERROR_NORETURN\n    \\hideinitializer\n */\n#ifndef RAPIDJSON_PARSE_ERROR\n#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \\\n    RAPIDJSON_MULTILINEMACRO_BEGIN \\\n    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \\\n    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \\\n    RAPIDJSON_MULTILINEMACRO_END\n#endif\n\n#include \"error/error.h\" // ParseErrorCode, ParseResult\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// ParseFlag\n\n/*! \\def RAPIDJSON_PARSE_DEFAULT_FLAGS\n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kParseDefaultFlags definition.\n\n    User can define this as any \\c ParseFlag combinations.\n*/\n#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS\n#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags\n#endif\n\n//! Combination of parseFlags\n/*! \\see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream\n */\nenum ParseFlag {\n    kParseNoFlags = 0,              //!< No flags are set.\n    kParseInsituFlag = 1,           //!< In-situ(destructive) parsing.\n    kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.\n    kParseIterativeFlag = 4,        //!< Iterative(constant complexity in terms of function call stack size) parsing.\n    kParseStopWhenDoneFlag = 8,     //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.\n    kParseFullPrecisionFlag = 16,   //!< Parse number in full precision (but slower).\n    kParseCommentsFlag = 32,        //!< Allow one-line (//) and multi-line (/**/) comments.\n    kParseNumbersAsStringsFlag = 64,    //!< Parse all numbers (ints/doubles) as strings.\n    kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.\n    kParseNanAndInfFlag = 256,      //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.\n    kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS  //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Handler\n\n/*! \\class rapidjson::Handler\n    \\brief Concept for receiving events from GenericReader upon parsing.\n    The functions return true if no error occurs. If they return false,\n    the event publisher should terminate the process.\n\\code\nconcept Handler {\n    typename Ch;\n\n    bool Null();\n    bool Bool(bool b);\n    bool Int(int i);\n    bool Uint(unsigned i);\n    bool Int64(int64_t i);\n    bool Uint64(uint64_t i);\n    bool Double(double d);\n    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)\n    bool RawNumber(const Ch* str, SizeType length, bool copy);\n    bool String(const Ch* str, SizeType length, bool copy);\n    bool StartObject();\n    bool Key(const Ch* str, SizeType length, bool copy);\n    bool EndObject(SizeType memberCount);\n    bool StartArray();\n    bool EndArray(SizeType elementCount);\n};\n\\endcode\n*/\n///////////////////////////////////////////////////////////////////////////////\n// BaseReaderHandler\n\n//! Default implementation of Handler.\n/*! This can be used as base class of any reader handler.\n    \\note implements Handler concept\n*/\ntemplate<typename Encoding = UTF8<>, typename Derived = void>\nstruct BaseReaderHandler {\n    typedef typename Encoding::Ch Ch;\n\n    typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;\n\n    bool Default() { return true; }\n    bool Null() { return static_cast<Override&>(*this).Default(); }\n    bool Bool(bool) { return static_cast<Override&>(*this).Default(); }\n    bool Int(int) { return static_cast<Override&>(*this).Default(); }\n    bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }\n    bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }\n    bool Double(double) { return static_cast<Override&>(*this).Default(); }\n    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)\n    bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }\n    bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }\n    bool StartObject() { return static_cast<Override&>(*this).Default(); }\n    bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }\n    bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }\n    bool StartArray() { return static_cast<Override&>(*this).Default(); }\n    bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// StreamLocalCopy\n\nnamespace internal {\n\ntemplate<typename Stream, int = StreamTraits<Stream>::copyOptimization>\nclass StreamLocalCopy;\n\n//! Do copy optimization.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 1> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original), original_(original) {}\n    ~StreamLocalCopy() { original_ = s; }\n\n    Stream s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n\n    Stream& original_;\n};\n\n//! Keep reference.\ntemplate<typename Stream>\nclass StreamLocalCopy<Stream, 0> {\npublic:\n    StreamLocalCopy(Stream& original) : s(original) {}\n\n    Stream& s;\n\nprivate:\n    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;\n};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// SkipWhitespace\n\n//! Skip the JSON white spaces in a stream.\n/*! \\param is A input stream for skipping white spaces.\n    \\note This function has SSE2/SSE4.2 specialization.\n*/\ntemplate<typename InputStream>\nvoid SkipWhitespace(InputStream& is) {\n    internal::StreamLocalCopy<InputStream> copy(is);\n    InputStream& s(copy.s);\n\n    typename InputStream::Ch c;\n    while ((c = s.Peek()) == ' ' || c == '\\n' || c == '\\r' || c == '\\t')\n        s.Take();\n}\n\ninline const char* SkipWhitespace(const char* p, const char* end) {\n    while (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    return p;\n}\n\n#ifdef RAPIDJSON_SSE42\n//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string using SIMD\n    static const char whitespace[16] = \" \\n\\r\\t\";\n    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));\n        if (r != 0) {   // some of characters is non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n}\n\ninline const char *SkipWhitespace_SIMD(const char* p, const char* end) {\n    // Fast return for single non-whitespace\n    if (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    else\n        return p;\n\n    // The middle of string using SIMD\n    static const char whitespace[16] = \" \\n\\r\\t\";\n    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));\n\n    for (; p <= end - 16; p += 16) {\n        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));\n        const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));\n        if (r != 0) {   // some of characters is non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n\n    return SkipWhitespace(p, end);\n}\n\n#elif defined(RAPIDJSON_SSE2)\n\n//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.\ninline const char *SkipWhitespace_SIMD(const char* p) {\n    // Fast return for single non-whitespace\n    if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n        ++p;\n    else\n        return p;\n\n    // 16-byte align to the next boundary\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    while (p != nextAligned)\n        if (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t')\n            ++p;\n        else\n            return p;\n\n    // The rest of string\n    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }\n    static const char whitespaces[4][16] = { C16(' '), C16('\\n'), C16('\\r'), C16('\\t') };\n    #undef C16\n\n    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));\n    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));\n    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));\n    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));\n\n    for (;; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        __m128i x = _mm_cmpeq_epi8(s, w0);\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));\n        if (r != 0) {   // some of characters may be non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n}\n\ninline const char *SkipWhitespace_SIMD(const char* p, const char* end) {\n    // Fast return for single non-whitespace\n    if (p != end && (*p == ' ' || *p == '\\n' || *p == '\\r' || *p == '\\t'))\n        ++p;\n    else\n        return p;\n\n    // The rest of string\n    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }\n    static const char whitespaces[4][16] = { C16(' '), C16('\\n'), C16('\\r'), C16('\\t') };\n    #undef C16\n\n    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));\n    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));\n    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));\n    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));\n\n    for (; p <= end - 16; p += 16) {\n        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));\n        __m128i x = _mm_cmpeq_epi8(s, w0);\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));\n        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));\n        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));\n        if (r != 0) {   // some of characters may be non-whitespace\n#ifdef _MSC_VER         // Find the index of first non-whitespace\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            return p + offset;\n#else\n            return p + __builtin_ffs(r) - 1;\n#endif\n        }\n    }\n\n    return SkipWhitespace(p, end);\n}\n\n#endif // RAPIDJSON_SSE2\n\n#ifdef RAPIDJSON_SIMD\n//! Template function specialization for InsituStringStream\ntemplate<> inline void SkipWhitespace(InsituStringStream& is) {\n    is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));\n}\n\n//! Template function specialization for StringStream\ntemplate<> inline void SkipWhitespace(StringStream& is) {\n    is.src_ = SkipWhitespace_SIMD(is.src_);\n}\n\ntemplate<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {\n    is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);\n}\n#endif // RAPIDJSON_SIMD\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericReader\n\n//! SAX-style JSON parser. Use \\ref Reader for UTF8 encoding and default allocator.\n/*! GenericReader parses JSON text from a stream, and send events synchronously to an\n    object implementing Handler concept.\n\n    It needs to allocate a stack for storing a single decoded string during\n    non-destructive parsing.\n\n    For in-situ parsing, the decoded string is directly written to the source\n    text string, no temporary buffer is required.\n\n    A GenericReader object can be reused for parsing multiple JSON text.\n\n    \\tparam SourceEncoding Encoding of the input stream.\n    \\tparam TargetEncoding Encoding of the parse output.\n    \\tparam StackAllocator Allocator type for stack.\n*/\ntemplate <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>\nclass GenericReader {\npublic:\n    typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type\n\n    //! Constructor.\n    /*! \\param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)\n        \\param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)\n    */\n    GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}\n\n    //! Parse JSON text.\n    /*! \\tparam parseFlags Combination of \\ref ParseFlag.\n        \\tparam InputStream Type of input stream, implementing Stream concept.\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        if (parseFlags & kParseIterativeFlag)\n            return IterativeParse<parseFlags>(is, handler);\n\n        parseResult_.Clear();\n\n        ClearStackOnExit scope(*this);\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n        if (RAPIDJSON_UNLIKELY(is.Peek() == '\\0')) {\n            RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        }\n        else {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n            if (!(parseFlags & kParseStopWhenDoneFlag)) {\n                SkipWhitespaceAndComments<parseFlags>(is);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n\n                if (RAPIDJSON_UNLIKELY(is.Peek() != '\\0')) {\n                    RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n                }\n            }\n        }\n\n        return parseResult_;\n    }\n\n    //! Parse JSON text (with \\ref kParseDefaultFlags)\n    /*! \\tparam InputStream Type of input stream, implementing Stream concept\n        \\tparam Handler Type of handler, implementing Handler concept.\n        \\param is Input stream to be parsed.\n        \\param handler The handler to receive events.\n        \\return Whether the parsing is successful.\n    */\n    template <typename InputStream, typename Handler>\n    ParseResult Parse(InputStream& is, Handler& handler) {\n        return Parse<kParseDefaultFlags>(is, handler);\n    }\n\n    //! Whether a parse error has occured in the last parsing.\n    bool HasParseError() const { return parseResult_.IsError(); }\n\n    //! Get the \\ref ParseErrorCode of last parsing.\n    ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }\n\n    //! Get the position of last parsing error in input, 0 otherwise.\n    size_t GetErrorOffset() const { return parseResult_.Offset(); }\n\nprotected:\n    void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericReader(const GenericReader&);\n    GenericReader& operator=(const GenericReader&);\n\n    void ClearStack() { stack_.Clear(); }\n\n    // clear stack on any exit from ParseStream, e.g. due to exception\n    struct ClearStackOnExit {\n        explicit ClearStackOnExit(GenericReader& r) : r_(r) {}\n        ~ClearStackOnExit() { r_.ClearStack(); }\n    private:\n        GenericReader& r_;\n        ClearStackOnExit(const ClearStackOnExit&);\n        ClearStackOnExit& operator=(const ClearStackOnExit&);\n    };\n\n    template<unsigned parseFlags, typename InputStream>\n    void SkipWhitespaceAndComments(InputStream& is) {\n        SkipWhitespace(is);\n\n        if (parseFlags & kParseCommentsFlag) {\n            while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {\n                if (Consume(is, '*')) {\n                    while (true) {\n                        if (RAPIDJSON_UNLIKELY(is.Peek() == '\\0'))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());\n                        else if (Consume(is, '*')) {\n                            if (Consume(is, '/'))\n                                break;\n                        }\n                        else\n                            is.Take();\n                    }\n                }\n                else if (RAPIDJSON_LIKELY(Consume(is, '/')))\n                    while (is.Peek() != '\\0' && is.Take() != '\\n');\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());\n\n                SkipWhitespace(is);\n            }\n        }\n    }\n\n    // Parse object: { string : value, ... }\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseObject(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '{');\n        is.Take();  // Skip '{'\n\n        if (RAPIDJSON_UNLIKELY(!handler.StartObject()))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n        if (Consume(is, '}')) {\n            if (RAPIDJSON_UNLIKELY(!handler.EndObject(0)))  // empty object\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType memberCount = 0;;) {\n            if (RAPIDJSON_UNLIKELY(is.Peek() != '\"'))\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());\n\n            ParseString<parseFlags>(is, handler, true);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))\n                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ++memberCount;\n\n            switch (is.Peek()) {\n                case ',':\n                    is.Take();\n                    SkipWhitespaceAndComments<parseFlags>(is);\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                    break;\n                case '}':\n                    is.Take();\n                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    return;\n                default:\n                    RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy\n            }\n\n            if (parseFlags & kParseTrailingCommasFlag) {\n                if (is.Peek() == '}') {\n                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    is.Take();\n                    return;\n                }\n            }\n        }\n    }\n\n    // Parse array: [ value, ... ]\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseArray(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == '[');\n        is.Take();  // Skip '['\n\n        if (RAPIDJSON_UNLIKELY(!handler.StartArray()))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n        if (Consume(is, ']')) {\n            if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n            return;\n        }\n\n        for (SizeType elementCount = 0;;) {\n            ParseValue<parseFlags>(is, handler);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            ++elementCount;\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n\n            if (Consume(is, ',')) {\n                SkipWhitespaceAndComments<parseFlags>(is);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            }\n            else if (Consume(is, ']')) {\n                if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                return;\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());\n\n            if (parseFlags & kParseTrailingCommasFlag) {\n                if (is.Peek() == ']') {\n                    if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))\n                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n                    is.Take();\n                    return;\n                }\n            }\n        }\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNull(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'n');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Null()))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseTrue(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 't');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseFalse(InputStream& is, Handler& handler) {\n        RAPIDJSON_ASSERT(is.Peek() == 'f');\n        is.Take();\n\n        if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {\n            if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))\n                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());\n    }\n\n    template<typename InputStream>\n    RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {\n        if (RAPIDJSON_LIKELY(is.Peek() == expect)) {\n            is.Take();\n            return true;\n        }\n        else\n            return false;\n    }\n\n    // Helper function to parse four hexidecimal digits in \\uXXXX in ParseString().\n    template<typename InputStream>\n    unsigned ParseHex4(InputStream& is, size_t escapeOffset) {\n        unsigned codepoint = 0;\n        for (int i = 0; i < 4; i++) {\n            Ch c = is.Peek();\n            codepoint <<= 4;\n            codepoint += static_cast<unsigned>(c);\n            if (c >= '0' && c <= '9')\n                codepoint -= '0';\n            else if (c >= 'A' && c <= 'F')\n                codepoint -= 'A' - 10;\n            else if (c >= 'a' && c <= 'f')\n                codepoint -= 'a' - 10;\n            else {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);\n                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);\n            }\n            is.Take();\n        }\n        return codepoint;\n    }\n\n    template <typename CharType>\n    class StackStream {\n    public:\n        typedef CharType Ch;\n\n        StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}\n        RAPIDJSON_FORCEINLINE void Put(Ch c) {\n            *stack_.template Push<Ch>() = c;\n            ++length_;\n        }\n\n        RAPIDJSON_FORCEINLINE void* Push(SizeType count) {\n            length_ += count;\n            return stack_.template Push<Ch>(count);\n        }\n\n        size_t Length() const { return length_; }\n\n        Ch* Pop() {\n            return stack_.template Pop<Ch>(length_);\n        }\n\n    private:\n        StackStream(const StackStream&);\n        StackStream& operator=(const StackStream&);\n\n        internal::Stack<StackAllocator>& stack_;\n        SizeType length_;\n    };\n\n    // Parse string and generate String event. Different code paths for kParseInsituFlag.\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseString(InputStream& is, Handler& handler, bool isKey = false) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        InputStream& s(copy.s);\n\n        RAPIDJSON_ASSERT(s.Peek() == '\\\"');\n        s.Take();  // Skip '\\\"'\n\n        bool success = false;\n        if (parseFlags & kParseInsituFlag) {\n            typename InputStream::Ch *head = s.PutBegin();\n            ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            size_t length = s.PutEnd(head) - 1;\n            RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n            const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);\n            success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));\n        }\n        else {\n            StackStream<typename TargetEncoding::Ch> stackStream(stack_);\n            ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n            SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;\n            const typename TargetEncoding::Ch* const str = stackStream.Pop();\n            success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));\n        }\n        if (RAPIDJSON_UNLIKELY(!success))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());\n    }\n\n    // Parse string to an output is\n    // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.\n    template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>\n    RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n        static const char escape[256] = {\n            Z16, Z16, 0, 0,'\\\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',\n            Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\\\', 0, 0, 0,\n            0, 0,'\\b', 0, 0, 0,'\\f', 0, 0, 0, 0, 0, 0, 0,'\\n', 0,\n            0, 0,'\\r', 0,'\\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16\n        };\n#undef Z16\n//!@endcond\n\n        for (;;) {\n            // Scan and copy string before \"\\\\\\\"\" or < 0x20. This is an optional optimzation.\n            if (!(parseFlags & kParseValidateEncodingFlag))\n                ScanCopyUnescapedString(is, os);\n\n            Ch c = is.Peek();\n            if (RAPIDJSON_UNLIKELY(c == '\\\\')) {    // Escape\n                size_t escapeOffset = is.Tell();    // For invalid escaping, report the inital '\\\\' as error offset\n                is.Take();\n                Ch e = is.Peek();\n                if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {\n                    is.Take();\n                    os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));\n                }\n                else if (RAPIDJSON_LIKELY(e == 'u')) {    // Unicode\n                    is.Take();\n                    unsigned codepoint = ParseHex4(is, escapeOffset);\n                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                    if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {\n                        // Handle UTF-16 surrogate pair\n                        if (RAPIDJSON_UNLIKELY(!Consume(is, '\\\\') || !Consume(is, 'u')))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);\n                        unsigned codepoint2 = ParseHex4(is, escapeOffset);\n                        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;\n                        if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);\n                        codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;\n                    }\n                    TEncoding::Encode(os, codepoint);\n                }\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);\n            }\n            else if (RAPIDJSON_UNLIKELY(c == '\"')) {    // Closing double quote\n                is.Take();\n                os.Put('\\0');   // null-terminate the string\n                return;\n            }\n            else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF\n                if (c == '\\0')\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());\n                else\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());\n            }\n            else {\n                size_t offset = is.Tell();\n                if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?\n                    !Transcoder<SEncoding, TEncoding>::Validate(is, os) :\n                    !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);\n            }\n        }\n    }\n\n    template<typename InputStream, typename OutputStream>\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {\n            // Do nothing for generic version\n    }\n\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\n    // StringStream -> StackStream<char>\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {\n        const char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                return;\n            }\n            else\n                os.Put(*p++);\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16]  = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                SizeType length;\n    #ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n    #else\n                length = static_cast<SizeType>(__builtin_ffs(r) - 1);\n    #endif\n                char* q = reinterpret_cast<char*>(os.Push(length));\n                for (size_t i = 0; i < length; i++)\n                    q[i] = p[i];\n\n                p += length;\n                break;\n            }\n            _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);\n        }\n\n        is.src_ = p;\n    }\n\n    // InsituStringStream -> InsituStringStream\n    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {\n        RAPIDJSON_ASSERT(&is == &os);\n        (void)os;\n\n        if (is.src_ == is.dst_) {\n            SkipUnescapedString(is);\n            return;\n        }\n\n        char* p = is.src_;\n        char *q = is.dst_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        while (p != nextAligned)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = p;\n                is.dst_ = q;\n                return;\n            }\n            else\n                *q++ = *p++;\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16, q += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                size_t length;\n#ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n#else\n                length = static_cast<size_t>(__builtin_ffs(r) - 1);\n#endif\n                for (const char* pend = p + length; p != pend; )\n                    *q++ = *p++;\n                break;\n            }\n            _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);\n        }\n\n        is.src_ = p;\n        is.dst_ = q;\n    }\n\n    // When read/write pointers are the same for insitu stream, just skip unescaped characters\n    static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {\n        RAPIDJSON_ASSERT(is.src_ == is.dst_);\n        char* p = is.src_;\n\n        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)\n        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n        for (; p != nextAligned; p++)\n            if (RAPIDJSON_UNLIKELY(*p == '\\\"') || RAPIDJSON_UNLIKELY(*p == '\\\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {\n                is.src_ = is.dst_ = p;\n                return;\n            }\n\n        // The rest of string using SIMD\n        static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n        static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n        static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };\n        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n        for (;; p += 16) {\n            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n            const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n            const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19\n            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n                size_t length;\n#ifdef _MSC_VER         // Find the index of first escaped\n                unsigned long offset;\n                _BitScanForward(&offset, r);\n                length = offset;\n#else\n                length = static_cast<size_t>(__builtin_ffs(r) - 1);\n#endif\n                p += length;\n                break;\n            }\n        }\n\n        is.src_ = is.dst_ = p;\n    }\n#endif\n\n    template<typename InputStream, bool backup, bool pushOnTake>\n    class NumberStream;\n\n    template<typename InputStream>\n    class NumberStream<InputStream, false, false> {\n    public:\n        typedef typename InputStream::Ch Ch;\n\n        NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader;  }\n        ~NumberStream() {}\n\n        RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }\n        RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }\n        RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }\n\t\t  RAPIDJSON_FORCEINLINE void Push(char) {}\n\n        size_t Tell() { return is.Tell(); }\n        size_t Length() { return 0; }\n        const char* Pop() { return 0; }\n\n    protected:\n        NumberStream& operator=(const NumberStream&);\n\n        InputStream& is;\n    };\n\n    template<typename InputStream>\n    class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {\n        typedef NumberStream<InputStream, false, false> Base;\n    public:\n        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}\n        ~NumberStream() {}\n\n        RAPIDJSON_FORCEINLINE Ch TakePush() {\n            stackStream.Put(static_cast<char>(Base::is.Peek()));\n            return Base::is.Take();\n        }\n\n        RAPIDJSON_FORCEINLINE void Push(char c) {\n            stackStream.Put(c);\n        }\n\n        size_t Length() { return stackStream.Length(); }\n\n        const char* Pop() {\n            stackStream.Put('\\0');\n            return stackStream.Pop();\n        }\n\n    private:\n        StackStream<char> stackStream;\n    };\n\n    template<typename InputStream>\n    class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {\n        typedef NumberStream<InputStream, true, false> Base;\n    public:\n        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}\n        ~NumberStream() {}\n\n        RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }\n    };\n\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseNumber(InputStream& is, Handler& handler) {\n        internal::StreamLocalCopy<InputStream> copy(is);\n        NumberStream<InputStream,\n            ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?\n                ((parseFlags & kParseInsituFlag) == 0) :\n                ((parseFlags & kParseFullPrecisionFlag) != 0),\n            (parseFlags & kParseNumbersAsStringsFlag) != 0 &&\n                (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);\n\n        size_t startOffset = s.Tell();\n        double d = 0.0;\n        bool useNanOrInf = false;\n\n        // Parse minus\n        bool minus = Consume(s, '-');\n\n        // Parse int: zero / ( digit1-9 *DIGIT )\n        unsigned i = 0;\n        uint64_t i64 = 0;\n        bool use64bit = false;\n        int significandDigit = 0;\n        if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {\n            i = 0;\n            s.TakePush();\n        }\n        else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {\n            i = static_cast<unsigned>(s.TakePush() - '0');\n\n            if (minus)\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648\n                        if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295\n                        if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {\n                            i64 = i;\n                            use64bit = true;\n                            break;\n                        }\n                    }\n                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n        // Parse NaN or Infinity here\n        else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {\n            useNanOrInf = true;\n            if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {\n                d = std::numeric_limits<double>::quiet_NaN();\n            }\n            else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {\n                d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());\n                if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')\n                                                            && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))\n                    RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n        }\n        else\n            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());\n\n        // Parse 64bit int\n        bool useDouble = false;\n        if (use64bit) {\n            if (minus)\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                     if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808\n                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {\n                            d = static_cast<double>(i64);\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n            else\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615\n                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {\n                            d = static_cast<double>(i64);\n                            useDouble = true;\n                            break;\n                        }\n                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                    significandDigit++;\n                }\n        }\n\n        // Force double for big integer\n        if (useDouble) {\n            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0\n                    RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);\n                d = d * 10 + (s.TakePush() - '0');\n            }\n        }\n\n        // Parse frac = decimal-point 1*DIGIT\n        int expFrac = 0;\n        size_t decimalPosition;\n        if (Consume(s, '.')) {\n            decimalPosition = s.Length();\n\n            if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());\n\n            if (!useDouble) {\n#if RAPIDJSON_64BIT\n                // Use i64 to store significand in 64-bit architecture\n                if (!use64bit)\n                    i64 = i;\n\n                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                    if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path\n                        break;\n                    else {\n                        i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');\n                        --expFrac;\n                        if (i64 != 0)\n                            significandDigit++;\n                    }\n                }\n\n                d = static_cast<double>(i64);\n#else\n                // Use double to store significand in 32-bit architecture\n                d = static_cast<double>(use64bit ? i64 : i);\n#endif\n                useDouble = true;\n            }\n\n            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                if (significandDigit < 17) {\n                    d = d * 10.0 + (s.TakePush() - '0');\n                    --expFrac;\n                    if (RAPIDJSON_LIKELY(d > 0.0))\n                        significandDigit++;\n                }\n                else\n                    s.TakePush();\n            }\n        }\n        else\n            decimalPosition = s.Length(); // decimal position at the end of integer.\n\n        // Parse exp = e [ minus / plus ] 1*DIGIT\n        int exp = 0;\n        if (Consume(s, 'e') || Consume(s, 'E')) {\n            if (!useDouble) {\n                d = static_cast<double>(use64bit ? i64 : i);\n                useDouble = true;\n            }\n\n            bool expMinus = false;\n            if (Consume(s, '+'))\n                ;\n            else if (Consume(s, '-'))\n                expMinus = true;\n\n            if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                exp = static_cast<int>(s.Take() - '0');\n                if (expMinus) {\n                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                        exp = exp * 10 + static_cast<int>(s.Take() - '0');\n                        if (exp >= 214748364) {                         // Issue #313: prevent overflow exponent\n                            while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9'))  // Consume the rest of exponent\n                                s.Take();\n                        }\n                    }\n                }\n                else {  // positive exp\n                    int maxExp = 308 - expFrac;\n                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {\n                        exp = exp * 10 + static_cast<int>(s.Take() - '0');\n                        if (RAPIDJSON_UNLIKELY(exp > maxExp))\n                            RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);\n                    }\n                }\n            }\n            else\n                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());\n\n            if (expMinus)\n                exp = -exp;\n        }\n\n        // Finish parsing, call event according to the type of number.\n        bool cont = true;\n\n        if (parseFlags & kParseNumbersAsStringsFlag) {\n            if (parseFlags & kParseInsituFlag) {\n                s.Pop();  // Pop stack no matter if it will be used or not.\n                typename InputStream::Ch* head = is.PutBegin();\n                const size_t length = s.Tell() - startOffset;\n                RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);\n                // unable to insert the \\0 character here, it will erase the comma after this number\n                const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);\n                cont = handler.RawNumber(str, SizeType(length), false);\n            }\n            else {\n                SizeType numCharsToCopy = static_cast<SizeType>(s.Length());\n                StringStream srcStream(s.Pop());\n                StackStream<typename TargetEncoding::Ch> dstStream(stack_);\n                while (numCharsToCopy--) {\n                    Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);\n                }\n                dstStream.Put('\\0');\n                const typename TargetEncoding::Ch* str = dstStream.Pop();\n                const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;\n                cont = handler.RawNumber(str, SizeType(length), true);\n            }\n        }\n        else {\n           size_t length = s.Length();\n           const char* decimal = s.Pop();  // Pop stack no matter if it will be used or not.\n\n           if (useDouble) {\n               int p = exp + expFrac;\n               if (parseFlags & kParseFullPrecisionFlag)\n                   d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);\n               else\n                   d = internal::StrtodNormalPrecision(d, p);\n\n               cont = handler.Double(minus ? -d : d);\n           }\n           else if (useNanOrInf) {\n               cont = handler.Double(d);\n           }\n           else {\n               if (use64bit) {\n                   if (minus)\n                       cont = handler.Int64(static_cast<int64_t>(~i64 + 1));\n                   else\n                       cont = handler.Uint64(i64);\n               }\n               else {\n                   if (minus)\n                       cont = handler.Int(static_cast<int32_t>(~i + 1));\n                   else\n                       cont = handler.Uint(i);\n               }\n           }\n        }\n        if (RAPIDJSON_UNLIKELY(!cont))\n            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);\n    }\n\n    // Parse any JSON value\n    template<unsigned parseFlags, typename InputStream, typename Handler>\n    void ParseValue(InputStream& is, Handler& handler) {\n        switch (is.Peek()) {\n            case 'n': ParseNull  <parseFlags>(is, handler); break;\n            case 't': ParseTrue  <parseFlags>(is, handler); break;\n            case 'f': ParseFalse <parseFlags>(is, handler); break;\n            case '\"': ParseString<parseFlags>(is, handler); break;\n            case '{': ParseObject<parseFlags>(is, handler); break;\n            case '[': ParseArray <parseFlags>(is, handler); break;\n            default :\n                      ParseNumber<parseFlags>(is, handler);\n                      break;\n\n        }\n    }\n\n    // Iterative Parsing\n\n    // States\n    enum IterativeParsingState {\n        IterativeParsingStartState = 0,\n        IterativeParsingFinishState,\n        IterativeParsingErrorState,\n\n        // Object states\n        IterativeParsingObjectInitialState,\n        IterativeParsingMemberKeyState,\n        IterativeParsingKeyValueDelimiterState,\n        IterativeParsingMemberValueState,\n        IterativeParsingMemberDelimiterState,\n        IterativeParsingObjectFinishState,\n\n        // Array states\n        IterativeParsingArrayInitialState,\n        IterativeParsingElementState,\n        IterativeParsingElementDelimiterState,\n        IterativeParsingArrayFinishState,\n\n        // Single value state\n        IterativeParsingValueState\n    };\n\n    enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };\n\n    // Tokens\n    enum Token {\n        LeftBracketToken = 0,\n        RightBracketToken,\n\n        LeftCurlyBracketToken,\n        RightCurlyBracketToken,\n\n        CommaToken,\n        ColonToken,\n\n        StringToken,\n        FalseToken,\n        TrueToken,\n        NullToken,\n        NumberToken,\n\n        kTokenCount\n    };\n\n    RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {\n\n//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN\n#define N NumberToken\n#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N\n        // Maps from ASCII to Token\n        static const unsigned char tokenMap[256] = {\n            N16, // 00~0F\n            N16, // 10~1F\n            N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F\n            N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F\n            N16, // 40~4F\n            N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F\n            N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F\n            N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F\n            N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF\n        };\n#undef N\n#undef N16\n//!@endcond\n\n        if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)\n            return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);\n        else\n            return NumberToken;\n    }\n\n    RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {\n        // current state x one lookahead token -> new state\n        static const char G[cIterativeParsingStateCount][kTokenCount] = {\n            // Start\n            {\n                IterativeParsingArrayInitialState,  // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingObjectInitialState, // Left curly bracket\n                IterativeParsingErrorState,         // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingValueState,         // String\n                IterativeParsingValueState,         // False\n                IterativeParsingValueState,         // True\n                IterativeParsingValueState,         // Null\n                IterativeParsingValueState          // Number\n            },\n            // Finish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Error(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ObjectInitial\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingObjectFinishState,  // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // MemberKey\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingKeyValueDelimiterState, // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // KeyValueDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push MemberValue state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingMemberValueState,       // String\n                IterativeParsingMemberValueState,       // False\n                IterativeParsingMemberValueState,       // True\n                IterativeParsingMemberValueState,       // Null\n                IterativeParsingMemberValueState        // Number\n            },\n            // MemberValue\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingErrorState,             // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingObjectFinishState,      // Right curly bracket\n                IterativeParsingMemberDelimiterState,   // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // MemberDelimiter\n            {\n                IterativeParsingErrorState,         // Left bracket\n                IterativeParsingErrorState,         // Right bracket\n                IterativeParsingErrorState,         // Left curly bracket\n                IterativeParsingObjectFinishState,  // Right curly bracket\n                IterativeParsingErrorState,         // Comma\n                IterativeParsingErrorState,         // Colon\n                IterativeParsingMemberKeyState,     // String\n                IterativeParsingErrorState,         // False\n                IterativeParsingErrorState,         // True\n                IterativeParsingErrorState,         // Null\n                IterativeParsingErrorState          // Number\n            },\n            // ObjectFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // ArrayInitial\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // Element\n            {\n                IterativeParsingErrorState,             // Left bracket\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingErrorState,             // Left curly bracket\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingElementDelimiterState,  // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingErrorState,             // String\n                IterativeParsingErrorState,             // False\n                IterativeParsingErrorState,             // True\n                IterativeParsingErrorState,             // Null\n                IterativeParsingErrorState              // Number\n            },\n            // ElementDelimiter\n            {\n                IterativeParsingArrayInitialState,      // Left bracket(push Element state)\n                IterativeParsingArrayFinishState,       // Right bracket\n                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)\n                IterativeParsingErrorState,             // Right curly bracket\n                IterativeParsingErrorState,             // Comma\n                IterativeParsingErrorState,             // Colon\n                IterativeParsingElementState,           // String\n                IterativeParsingElementState,           // False\n                IterativeParsingElementState,           // True\n                IterativeParsingElementState,           // Null\n                IterativeParsingElementState            // Number\n            },\n            // ArrayFinish(sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            },\n            // Single Value (sink state)\n            {\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,\n                IterativeParsingErrorState\n            }\n        }; // End of G\n\n        return static_cast<IterativeParsingState>(G[state][token]);\n    }\n\n    // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().\n    // May return a new state on state pop.\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {\n        (void)token;\n\n        switch (dst) {\n        case IterativeParsingErrorState:\n            return dst;\n\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingArrayInitialState:\n        {\n            // Push the state(Element or MemeberValue) if we are nested in another array or value of member.\n            // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.\n            IterativeParsingState n = src;\n            if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)\n                n = IterativeParsingElementState;\n            else if (src == IterativeParsingKeyValueDelimiterState)\n                n = IterativeParsingMemberValueState;\n            // Push current state.\n            *stack_.template Push<SizeType>(1) = n;\n            // Initialize and push the member/element count.\n            *stack_.template Push<SizeType>(1) = 0;\n            // Call handler\n            bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return dst;\n            }\n        }\n\n        case IterativeParsingMemberKeyState:\n            ParseString<parseFlags>(is, handler, true);\n            if (HasParseError())\n                return IterativeParsingErrorState;\n            else\n                return dst;\n\n        case IterativeParsingKeyValueDelimiterState:\n            RAPIDJSON_ASSERT(token == ColonToken);\n            is.Take();\n            return dst;\n\n        case IterativeParsingMemberValueState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingElementState:\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return dst;\n\n        case IterativeParsingMemberDelimiterState:\n        case IterativeParsingElementDelimiterState:\n            is.Take();\n            // Update member/element count.\n            *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;\n            return dst;\n\n        case IterativeParsingObjectFinishState:\n        {\n            // Transit from delimiter is only allowed when trailing commas are enabled\n            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            // Get member count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the object is not empty, count the last member.\n            if (src == IterativeParsingMemberValueState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndObject(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        case IterativeParsingArrayFinishState:\n        {\n            // Transit from delimiter is only allowed when trailing commas are enabled\n            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            // Get element count.\n            SizeType c = *stack_.template Pop<SizeType>(1);\n            // If the array is not empty, count the last element.\n            if (src == IterativeParsingElementState)\n                ++c;\n            // Restore the state.\n            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));\n            // Transit to Finish state if this is the topmost scope.\n            if (n == IterativeParsingStartState)\n                n = IterativeParsingFinishState;\n            // Call handler\n            bool hr = handler.EndArray(c);\n            // On handler short circuits the parsing.\n            if (!hr) {\n                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());\n                return IterativeParsingErrorState;\n            }\n            else {\n                is.Take();\n                return n;\n            }\n        }\n\n        default:\n            // This branch is for IterativeParsingValueState actually.\n            // Use `default:` rather than\n            // `case IterativeParsingValueState:` is for code coverage.\n\n            // The IterativeParsingStartState is not enumerated in this switch-case.\n            // It is impossible for that case. And it can be caught by following assertion.\n\n            // The IterativeParsingFinishState is not enumerated in this switch-case either.\n            // It is a \"derivative\" state which cannot triggered from Predict() directly.\n            // Therefore it cannot happen here. And it can be caught by following assertion.\n            RAPIDJSON_ASSERT(dst == IterativeParsingValueState);\n\n            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.\n            ParseValue<parseFlags>(is, handler);\n            if (HasParseError()) {\n                return IterativeParsingErrorState;\n            }\n            return IterativeParsingFinishState;\n        }\n    }\n\n    template <typename InputStream>\n    void HandleError(IterativeParsingState src, InputStream& is) {\n        if (HasParseError()) {\n            // Error flag has been set.\n            return;\n        }\n\n        switch (src) {\n        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;\n        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;\n        case IterativeParsingObjectInitialState:\n        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;\n        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;\n        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;\n        case IterativeParsingKeyValueDelimiterState:\n        case IterativeParsingArrayInitialState:\n        case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;\n        default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;\n        }\n    }\n\n    template <unsigned parseFlags, typename InputStream, typename Handler>\n    ParseResult IterativeParse(InputStream& is, Handler& handler) {\n        parseResult_.Clear();\n        ClearStackOnExit scope(*this);\n        IterativeParsingState state = IterativeParsingStartState;\n\n        SkipWhitespaceAndComments<parseFlags>(is);\n        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        while (is.Peek() != '\\0') {\n            Token t = Tokenize(is.Peek());\n            IterativeParsingState n = Predict(state, t);\n            IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);\n\n            if (d == IterativeParsingErrorState) {\n                HandleError(state, is);\n                break;\n            }\n\n            state = d;\n\n            // Do not further consume streams if a root JSON has been parsed.\n            if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)\n                break;\n\n            SkipWhitespaceAndComments<parseFlags>(is);\n            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);\n        }\n\n        // Handle the end of file.\n        if (state != IterativeParsingFinishState)\n            HandleError(state, is);\n\n        return parseResult_;\n    }\n\n    static const size_t kDefaultStackCapacity = 256;    //!< Default stack capacity in bytes for storing a single decoded string.\n    internal::Stack<StackAllocator> stack_;  //!< A stack for storing decoded string temporarily during non-destructive parsing.\n    ParseResult parseResult_;\n}; // class GenericReader\n\n//! Reader with UTF8 encoding and default allocator.\ntypedef GenericReader<UTF8<>, UTF8<> > Reader;\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n\n#ifdef __GNUC__\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_READER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/schema.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available->\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License-> You may obtain a copy of the License at\n//\n// http://opensource->org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied-> See the License for the \n// specific language governing permissions and limitations under the License->\n\n#ifndef RAPIDJSON_SCHEMA_H_\n#define RAPIDJSON_SCHEMA_H_\n\n#include \"document.h\"\n#include \"pointer.h\"\n#include <cmath> // abs, floor\n\n#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)\n#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1\n#else\n#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0\n#endif\n\n#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))\n#define RAPIDJSON_SCHEMA_USE_STDREGEX 1\n#else\n#define RAPIDJSON_SCHEMA_USE_STDREGEX 0\n#endif\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n#include \"internal/regex.h\"\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n#include <regex>\n#endif\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX\n#define RAPIDJSON_SCHEMA_HAS_REGEX 1\n#else\n#define RAPIDJSON_SCHEMA_HAS_REGEX 0\n#endif\n\n#ifndef RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_SCHEMA_VERBOSE 0\n#endif\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#include \"stringbuffer.h\"\n#endif\n\nRAPIDJSON_DIAG_PUSH\n\n#if defined(__GNUC__)\nRAPIDJSON_DIAG_OFF(effc++)\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_OFF(weak-vtables)\nRAPIDJSON_DIAG_OFF(exit-time-destructors)\nRAPIDJSON_DIAG_OFF(c++98-compat-pedantic)\nRAPIDJSON_DIAG_OFF(variadic-macros)\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// Verbose Utilities\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n\nnamespace internal {\n\ninline void PrintInvalidKeyword(const char* keyword) {\n    printf(\"Fail keyword: %s\\n\", keyword);\n}\n\ninline void PrintInvalidKeyword(const wchar_t* keyword) {\n    wprintf(L\"Fail keyword: %ls\\n\", keyword);\n}\n\ninline void PrintInvalidDocument(const char* document) {\n    printf(\"Fail document: %s\\n\\n\", document);\n}\n\ninline void PrintInvalidDocument(const wchar_t* document) {\n    wprintf(L\"Fail document: %ls\\n\\n\", document);\n}\n\ninline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {\n    printf(\"S: %*s%s\\nD: %*s%s\\n\\n\", depth * 4, \" \", s, depth * 4, \" \", d);\n}\n\ninline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {\n    wprintf(L\"S: %*ls%ls\\nD: %*ls%ls\\n\\n\", depth * 4, L\" \", s, depth * 4, L\" \", d);\n}\n\n} // namespace internal\n\n#endif // RAPIDJSON_SCHEMA_VERBOSE\n\n///////////////////////////////////////////////////////////////////////////////\n// RAPIDJSON_INVALID_KEYWORD_RETURN\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)\n#else\n#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)\n#endif\n\n#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\\\nRAPIDJSON_MULTILINEMACRO_BEGIN\\\n    context.invalidKeyword = keyword.GetString();\\\n    RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\\\n    return false;\\\nRAPIDJSON_MULTILINEMACRO_END\n\n///////////////////////////////////////////////////////////////////////////////\n// Forward declarations\n\ntemplate <typename ValueType, typename Allocator>\nclass GenericSchemaDocument;\n\nnamespace internal {\n\ntemplate <typename SchemaDocumentType>\nclass Schema;\n\n///////////////////////////////////////////////////////////////////////////////\n// ISchemaValidator\n\nclass ISchemaValidator {\npublic:\n    virtual ~ISchemaValidator() {}\n    virtual bool IsValid() const = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// ISchemaStateFactory\n\ntemplate <typename SchemaType>\nclass ISchemaStateFactory {\npublic:\n    virtual ~ISchemaStateFactory() {}\n    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;\n    virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;\n    virtual void* CreateHasher() = 0;\n    virtual uint64_t GetHashCode(void* hasher) = 0;\n    virtual void DestroryHasher(void* hasher) = 0;\n    virtual void* MallocState(size_t size) = 0;\n    virtual void FreeState(void* p) = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Hasher\n\n// For comparison of compound value\ntemplate<typename Encoding, typename Allocator>\nclass Hasher {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}\n\n    bool Null() { return WriteType(kNullType); }\n    bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }\n    bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }\n    bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }\n    bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }\n    bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }\n    bool Double(double d) { \n        Number n; \n        if (d < 0) n.u.i = static_cast<int64_t>(d);\n        else       n.u.u = static_cast<uint64_t>(d); \n        n.d = d;\n        return WriteNumber(n);\n    }\n\n    bool RawNumber(const Ch* str, SizeType len, bool) {\n        WriteBuffer(kNumberType, str, len * sizeof(Ch));\n        return true;\n    }\n\n    bool String(const Ch* str, SizeType len, bool) {\n        WriteBuffer(kStringType, str, len * sizeof(Ch));\n        return true;\n    }\n\n    bool StartObject() { return true; }\n    bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }\n    bool EndObject(SizeType memberCount) { \n        uint64_t h = Hash(0, kObjectType);\n        uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);\n        for (SizeType i = 0; i < memberCount; i++)\n            h ^= Hash(kv[i * 2], kv[i * 2 + 1]);  // Use xor to achieve member order insensitive\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n    \n    bool StartArray() { return true; }\n    bool EndArray(SizeType elementCount) { \n        uint64_t h = Hash(0, kArrayType);\n        uint64_t* e = stack_.template Pop<uint64_t>(elementCount);\n        for (SizeType i = 0; i < elementCount; i++)\n            h = Hash(h, e[i]); // Use hash to achieve element order sensitive\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n\n    bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }\n\n    uint64_t GetHashCode() const {\n        RAPIDJSON_ASSERT(IsValid());\n        return *stack_.template Top<uint64_t>();\n    }\n\nprivate:\n    static const size_t kDefaultSize = 256;\n    struct Number {\n        union U {\n            uint64_t u;\n            int64_t i;\n        }u;\n        double d;\n    };\n\n    bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }\n    \n    bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }\n    \n    bool WriteBuffer(Type type, const void* data, size_t len) {\n        // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/\n        uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);\n        const unsigned char* d = static_cast<const unsigned char*>(data);\n        for (size_t i = 0; i < len; i++)\n            h = Hash(h, d[i]);\n        *stack_.template Push<uint64_t>() = h;\n        return true;\n    }\n\n    static uint64_t Hash(uint64_t h, uint64_t d) {\n        static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);\n        h ^= d;\n        h *= kPrime;\n        return h;\n    }\n\n    Stack<Allocator> stack_;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// SchemaValidationContext\n\ntemplate <typename SchemaDocumentType>\nstruct SchemaValidationContext {\n    typedef Schema<SchemaDocumentType> SchemaType;\n    typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;\n    typedef typename SchemaType::ValueType ValueType;\n    typedef typename ValueType::Ch Ch;\n\n    enum PatternValidatorType {\n        kPatternValidatorOnly,\n        kPatternValidatorWithProperty,\n        kPatternValidatorWithAdditionalProperty\n    };\n\n    SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :\n        factory(f),\n        schema(s),\n        valueSchema(),\n        invalidKeyword(),\n        hasher(),\n        arrayElementHashCodes(),\n        validators(),\n        validatorCount(),\n        patternPropertiesValidators(),\n        patternPropertiesValidatorCount(),\n        patternPropertiesSchemas(),\n        patternPropertiesSchemaCount(),\n        valuePatternValidatorType(kPatternValidatorOnly),\n        propertyExist(),\n        inArray(false),\n        valueUniqueness(false),\n        arrayUniqueness(false)\n    {\n    }\n\n    ~SchemaValidationContext() {\n        if (hasher)\n            factory.DestroryHasher(hasher);\n        if (validators) {\n            for (SizeType i = 0; i < validatorCount; i++)\n                factory.DestroySchemaValidator(validators[i]);\n            factory.FreeState(validators);\n        }\n        if (patternPropertiesValidators) {\n            for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)\n                factory.DestroySchemaValidator(patternPropertiesValidators[i]);\n            factory.FreeState(patternPropertiesValidators);\n        }\n        if (patternPropertiesSchemas)\n            factory.FreeState(patternPropertiesSchemas);\n        if (propertyExist)\n            factory.FreeState(propertyExist);\n    }\n\n    SchemaValidatorFactoryType& factory;\n    const SchemaType* schema;\n    const SchemaType* valueSchema;\n    const Ch* invalidKeyword;\n    void* hasher; // Only validator access\n    void* arrayElementHashCodes; // Only validator access this\n    ISchemaValidator** validators;\n    SizeType validatorCount;\n    ISchemaValidator** patternPropertiesValidators;\n    SizeType patternPropertiesValidatorCount;\n    const SchemaType** patternPropertiesSchemas;\n    SizeType patternPropertiesSchemaCount;\n    PatternValidatorType valuePatternValidatorType;\n    PatternValidatorType objectPatternValidatorType;\n    SizeType arrayElementIndex;\n    bool* propertyExist;\n    bool inArray;\n    bool valueUniqueness;\n    bool arrayUniqueness;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// Schema\n\ntemplate <typename SchemaDocumentType>\nclass Schema {\npublic:\n    typedef typename SchemaDocumentType::ValueType ValueType;\n    typedef typename SchemaDocumentType::AllocatorType AllocatorType;\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename EncodingType::Ch Ch;\n    typedef SchemaValidationContext<SchemaDocumentType> Context;\n    typedef Schema<SchemaDocumentType> SchemaType;\n    typedef GenericValue<EncodingType, AllocatorType> SValue;\n    friend class GenericSchemaDocument<ValueType, AllocatorType>;\n\n    Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :\n        allocator_(allocator),\n        enum_(),\n        enumCount_(),\n        not_(),\n        type_((1 << kTotalSchemaType) - 1), // typeless\n        validatorCount_(),\n        properties_(),\n        additionalPropertiesSchema_(),\n        patternProperties_(),\n        patternPropertyCount_(),\n        propertyCount_(),\n        minProperties_(),\n        maxProperties_(SizeType(~0)),\n        additionalProperties_(true),\n        hasDependencies_(),\n        hasRequired_(),\n        hasSchemaDependencies_(),\n        additionalItemsSchema_(),\n        itemsList_(),\n        itemsTuple_(),\n        itemsTupleCount_(),\n        minItems_(),\n        maxItems_(SizeType(~0)),\n        additionalItems_(true),\n        uniqueItems_(false),\n        pattern_(),\n        minLength_(0),\n        maxLength_(~SizeType(0)),\n        exclusiveMinimum_(false),\n        exclusiveMaximum_(false)\n    {\n        typedef typename SchemaDocumentType::ValueType ValueType;\n        typedef typename ValueType::ConstValueIterator ConstValueIterator;\n        typedef typename ValueType::ConstMemberIterator ConstMemberIterator;\n\n        if (!value.IsObject())\n            return;\n\n        if (const ValueType* v = GetMember(value, GetTypeString())) {\n            type_ = 0;\n            if (v->IsString())\n                AddType(*v);\n            else if (v->IsArray())\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)\n                    AddType(*itr);\n        }\n\n        if (const ValueType* v = GetMember(value, GetEnumString()))\n            if (v->IsArray() && v->Size() > 0) {\n                enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {\n                    typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;\n                    char buffer[256 + 24];\n                    MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));\n                    EnumHasherType h(&hasherAllocator, 256);\n                    itr->Accept(h);\n                    enum_[enumCount_++] = h.GetHashCode();\n                }\n            }\n\n        if (schemaDocument) {\n            AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);\n            AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);\n            AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);\n        }\n\n        if (const ValueType* v = GetMember(value, GetNotString())) {\n            schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);\n            notValidatorIndex_ = validatorCount_;\n            validatorCount_++;\n        }\n\n        // Object\n\n        const ValueType* properties = GetMember(value, GetPropertiesString());\n        const ValueType* required = GetMember(value, GetRequiredString());\n        const ValueType* dependencies = GetMember(value, GetDependenciesString());\n        {\n            // Gather properties from properties/required/dependencies\n            SValue allProperties(kArrayType);\n\n            if (properties && properties->IsObject())\n                for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)\n                    AddUniqueElement(allProperties, itr->name);\n            \n            if (required && required->IsArray())\n                for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)\n                    if (itr->IsString())\n                        AddUniqueElement(allProperties, *itr);\n\n            if (dependencies && dependencies->IsObject())\n                for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {\n                    AddUniqueElement(allProperties, itr->name);\n                    if (itr->value.IsArray())\n                        for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)\n                            if (i->IsString())\n                                AddUniqueElement(allProperties, *i);\n                }\n\n            if (allProperties.Size() > 0) {\n                propertyCount_ = allProperties.Size();\n                properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));\n                for (SizeType i = 0; i < propertyCount_; i++) {\n                    new (&properties_[i]) Property();\n                    properties_[i].name = allProperties[i];\n                    properties_[i].schema = GetTypeless();\n                }\n            }\n        }\n\n        if (properties && properties->IsObject()) {\n            PointerType q = p.Append(GetPropertiesString(), allocator_);\n            for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {\n                SizeType index;\n                if (FindPropertyIndex(itr->name, &index))\n                    schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);\n            }\n        }\n\n        if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {\n            PointerType q = p.Append(GetPatternPropertiesString(), allocator_);\n            patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));\n            patternPropertyCount_ = 0;\n\n            for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {\n                new (&patternProperties_[patternPropertyCount_]) PatternProperty();\n                patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);\n                schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);\n                patternPropertyCount_++;\n            }\n        }\n\n        if (required && required->IsArray())\n            for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)\n                if (itr->IsString()) {\n                    SizeType index;\n                    if (FindPropertyIndex(*itr, &index)) {\n                        properties_[index].required = true;\n                        hasRequired_ = true;\n                    }\n                }\n\n        if (dependencies && dependencies->IsObject()) {\n            PointerType q = p.Append(GetDependenciesString(), allocator_);\n            hasDependencies_ = true;\n            for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {\n                SizeType sourceIndex;\n                if (FindPropertyIndex(itr->name, &sourceIndex)) {\n                    if (itr->value.IsArray()) {\n                        properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));\n                        std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);\n                        for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {\n                            SizeType targetIndex;\n                            if (FindPropertyIndex(*targetItr, &targetIndex))\n                                properties_[sourceIndex].dependencies[targetIndex] = true;\n                        }\n                    }\n                    else if (itr->value.IsObject()) {\n                        hasSchemaDependencies_ = true;\n                        schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);\n                        properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;\n                        validatorCount_++;\n                    }\n                }\n            }\n        }\n\n        if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {\n            if (v->IsBool())\n                additionalProperties_ = v->GetBool();\n            else if (v->IsObject())\n                schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);\n        }\n\n        AssignIfExist(minProperties_, value, GetMinPropertiesString());\n        AssignIfExist(maxProperties_, value, GetMaxPropertiesString());\n\n        // Array\n        if (const ValueType* v = GetMember(value, GetItemsString())) {\n            PointerType q = p.Append(GetItemsString(), allocator_);\n            if (v->IsObject()) // List validation\n                schemaDocument->CreateSchema(&itemsList_, q, *v, document);\n            else if (v->IsArray()) { // Tuple validation\n                itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));\n                SizeType index = 0;\n                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)\n                    schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);\n            }\n        }\n\n        AssignIfExist(minItems_, value, GetMinItemsString());\n        AssignIfExist(maxItems_, value, GetMaxItemsString());\n\n        if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {\n            if (v->IsBool())\n                additionalItems_ = v->GetBool();\n            else if (v->IsObject())\n                schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);\n        }\n\n        AssignIfExist(uniqueItems_, value, GetUniqueItemsString());\n\n        // String\n        AssignIfExist(minLength_, value, GetMinLengthString());\n        AssignIfExist(maxLength_, value, GetMaxLengthString());\n\n        if (const ValueType* v = GetMember(value, GetPatternString()))\n            pattern_ = CreatePattern(*v);\n\n        // Number\n        if (const ValueType* v = GetMember(value, GetMinimumString()))\n            if (v->IsNumber())\n                minimum_.CopyFrom(*v, *allocator_);\n\n        if (const ValueType* v = GetMember(value, GetMaximumString()))\n            if (v->IsNumber())\n                maximum_.CopyFrom(*v, *allocator_);\n\n        AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());\n        AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());\n\n        if (const ValueType* v = GetMember(value, GetMultipleOfString()))\n            if (v->IsNumber() && v->GetDouble() > 0.0)\n                multipleOf_.CopyFrom(*v, *allocator_);\n    }\n\n    ~Schema() {\n        if (allocator_) {\n            allocator_->Free(enum_);\n        }\n        if (properties_) {\n            for (SizeType i = 0; i < propertyCount_; i++)\n                properties_[i].~Property();\n            AllocatorType::Free(properties_);\n        }\n        if (patternProperties_) {\n            for (SizeType i = 0; i < patternPropertyCount_; i++)\n                patternProperties_[i].~PatternProperty();\n            AllocatorType::Free(patternProperties_);\n        }\n        AllocatorType::Free(itemsTuple_);\n#if RAPIDJSON_SCHEMA_HAS_REGEX\n        if (pattern_) {\n            pattern_->~RegexType();\n            allocator_->Free(pattern_);\n        }\n#endif\n    }\n\n    bool BeginValue(Context& context) const {\n        if (context.inArray) {\n            if (uniqueItems_)\n                context.valueUniqueness = true;\n\n            if (itemsList_)\n                context.valueSchema = itemsList_;\n            else if (itemsTuple_) {\n                if (context.arrayElementIndex < itemsTupleCount_)\n                    context.valueSchema = itemsTuple_[context.arrayElementIndex];\n                else if (additionalItemsSchema_)\n                    context.valueSchema = additionalItemsSchema_;\n                else if (additionalItems_)\n                    context.valueSchema = GetTypeless();\n                else\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());\n            }\n            else\n                context.valueSchema = GetTypeless();\n\n            context.arrayElementIndex++;\n        }\n        return true;\n    }\n\n    RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {\n        if (context.patternPropertiesValidatorCount > 0) {\n            bool otherValid = false;\n            SizeType count = context.patternPropertiesValidatorCount;\n            if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)\n                otherValid = context.patternPropertiesValidators[--count]->IsValid();\n\n            bool patternValid = true;\n            for (SizeType i = 0; i < count; i++)\n                if (!context.patternPropertiesValidators[i]->IsValid()) {\n                    patternValid = false;\n                    break;\n                }\n\n            if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {\n                if (!patternValid)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n            }\n            else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {\n                if (!patternValid || !otherValid)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n            }\n            else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());\n        }\n\n        if (enum_) {\n            const uint64_t h = context.factory.GetHashCode(context.hasher);\n            for (SizeType i = 0; i < enumCount_; i++)\n                if (enum_[i] == h)\n                    goto foundEnum;\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());\n            foundEnum:;\n        }\n\n        if (allOf_.schemas)\n            for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)\n                if (!context.validators[i]->IsValid())\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());\n        \n        if (anyOf_.schemas) {\n            for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)\n                if (context.validators[i]->IsValid())\n                    goto foundAny;\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());\n            foundAny:;\n        }\n\n        if (oneOf_.schemas) {\n            bool oneValid = false;\n            for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)\n                if (context.validators[i]->IsValid()) {\n                    if (oneValid)\n                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());\n                    else\n                        oneValid = true;\n                }\n            if (!oneValid)\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());\n        }\n\n        if (not_ && context.validators[notValidatorIndex_]->IsValid())\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());\n\n        return true;\n    }\n\n    bool Null(Context& context) const { \n        if (!(type_ & (1 << kNullSchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        return CreateParallelValidator(context);\n    }\n    \n    bool Bool(Context& context, bool) const { \n        if (!(type_ & (1 << kBooleanSchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n        return CreateParallelValidator(context);\n    }\n\n    bool Int(Context& context, int i) const {\n        if (!CheckInt(context, i))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Uint(Context& context, unsigned u) const {\n        if (!CheckUint(context, u))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Int64(Context& context, int64_t i) const {\n        if (!CheckInt(context, i))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Uint64(Context& context, uint64_t u) const {\n        if (!CheckUint(context, u))\n            return false;\n        return CreateParallelValidator(context);\n    }\n\n    bool Double(Context& context, double d) const {\n        if (!(type_ & (1 << kNumberSchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))\n            return false;\n\n        if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))\n            return false;\n        \n        if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))\n            return false;\n        \n        return CreateParallelValidator(context);\n    }\n    \n    bool String(Context& context, const Ch* str, SizeType length, bool) const {\n        if (!(type_ & (1 << kStringSchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        if (minLength_ != 0 || maxLength_ != SizeType(~0)) {\n            SizeType count;\n            if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {\n                if (count < minLength_)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());\n                if (count > maxLength_)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());\n            }\n        }\n\n        if (pattern_ && !IsPatternMatch(pattern_, str, length))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());\n\n        return CreateParallelValidator(context);\n    }\n\n    bool StartObject(Context& context) const { \n        if (!(type_ & (1 << kObjectSchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        if (hasDependencies_ || hasRequired_) {\n            context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));\n            std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);\n        }\n\n        if (patternProperties_) { // pre-allocate schema array\n            SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType\n            context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));\n            context.patternPropertiesSchemaCount = 0;\n            std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);\n        }\n\n        return CreateParallelValidator(context);\n    }\n    \n    bool Key(Context& context, const Ch* str, SizeType len, bool) const {\n        if (patternProperties_) {\n            context.patternPropertiesSchemaCount = 0;\n            for (SizeType i = 0; i < patternPropertyCount_; i++)\n                if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))\n                    context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;\n        }\n\n        SizeType index;\n        if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {\n            if (context.patternPropertiesSchemaCount > 0) {\n                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;\n                context.valueSchema = GetTypeless();\n                context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;\n            }\n            else\n                context.valueSchema = properties_[index].schema;\n\n            if (context.propertyExist)\n                context.propertyExist[index] = true;\n\n            return true;\n        }\n\n        if (additionalPropertiesSchema_) {\n            if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {\n                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;\n                context.valueSchema = GetTypeless();\n                context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;\n            }\n            else\n                context.valueSchema = additionalPropertiesSchema_;\n            return true;\n        }\n        else if (additionalProperties_) {\n            context.valueSchema = GetTypeless();\n            return true;\n        }\n\n        if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());\n\n        return true;\n    }\n\n    bool EndObject(Context& context, SizeType memberCount) const {\n        if (hasRequired_)\n            for (SizeType index = 0; index < propertyCount_; index++)\n                if (properties_[index].required)\n                    if (!context.propertyExist[index])\n                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());\n\n        if (memberCount < minProperties_)\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());\n\n        if (memberCount > maxProperties_)\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());\n\n        if (hasDependencies_) {\n            for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)\n                if (context.propertyExist[sourceIndex]) {\n                    if (properties_[sourceIndex].dependencies) {\n                        for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)\n                            if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])\n                                RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());\n                    }\n                    else if (properties_[sourceIndex].dependenciesSchema)\n                        if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())\n                            RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());\n                }\n        }\n\n        return true;\n    }\n\n    bool StartArray(Context& context) const { \n        if (!(type_ & (1 << kArraySchemaType)))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        context.arrayElementIndex = 0;\n        context.inArray = true;\n\n        return CreateParallelValidator(context);\n    }\n\n    bool EndArray(Context& context, SizeType elementCount) const { \n        context.inArray = false;\n        \n        if (elementCount < minItems_)\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());\n        \n        if (elementCount > maxItems_)\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());\n\n        return true;\n    }\n\n    // Generate functions for string literal according to Ch\n#define RAPIDJSON_STRING_(name, ...) \\\n    static const ValueType& Get##name##String() {\\\n        static const Ch s[] = { __VA_ARGS__, '\\0' };\\\n        static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\\\n        return v;\\\n    }\n\n    RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')\n    RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')\n    RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')\n    RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')\n    RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')\n    RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')\n    RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')\n    RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')\n    RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')\n    RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')\n    RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')\n    RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')\n    RAPIDJSON_STRING_(Not, 'n', 'o', 't')\n    RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')\n    RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')\n    RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')\n    RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')\n    RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')\n    RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')\n    RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')\n    RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')\n    RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')\n\n#undef RAPIDJSON_STRING_\n\nprivate:\n    enum SchemaValueType {\n        kNullSchemaType,\n        kBooleanSchemaType,\n        kObjectSchemaType,\n        kArraySchemaType,\n        kStringSchemaType,\n        kNumberSchemaType,\n        kIntegerSchemaType,\n        kTotalSchemaType\n    };\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n        typedef internal::GenericRegex<EncodingType> RegexType;\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n        typedef std::basic_regex<Ch> RegexType;\n#else\n        typedef char RegexType;\n#endif\n\n    struct SchemaArray {\n        SchemaArray() : schemas(), count() {}\n        ~SchemaArray() { AllocatorType::Free(schemas); }\n        const SchemaType** schemas;\n        SizeType begin; // begin index of context.validators\n        SizeType count;\n    };\n\n    static const SchemaType* GetTypeless() {\n        static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);\n        return &typeless;\n    }\n\n    template <typename V1, typename V2>\n    void AddUniqueElement(V1& a, const V2& v) {\n        for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)\n            if (*itr == v)\n                return;\n        V1 c(v, *allocator_);\n        a.PushBack(c, *allocator_);\n    }\n\n    static const ValueType* GetMember(const ValueType& value, const ValueType& name) {\n        typename ValueType::ConstMemberIterator itr = value.FindMember(name);\n        return itr != value.MemberEnd() ? &(itr->value) : 0;\n    }\n\n    static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {\n        if (const ValueType* v = GetMember(value, name))\n            if (v->IsBool())\n                out = v->GetBool();\n    }\n\n    static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {\n        if (const ValueType* v = GetMember(value, name))\n            if (v->IsUint64() && v->GetUint64() <= SizeType(~0))\n                out = static_cast<SizeType>(v->GetUint64());\n    }\n\n    void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {\n        if (const ValueType* v = GetMember(value, name)) {\n            if (v->IsArray() && v->Size() > 0) {\n                PointerType q = p.Append(name, allocator_);\n                out.count = v->Size();\n                out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));\n                memset(out.schemas, 0, sizeof(Schema*)* out.count);\n                for (SizeType i = 0; i < out.count; i++)\n                    schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);\n                out.begin = validatorCount_;\n                validatorCount_ += out.count;\n            }\n        }\n    }\n\n#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType& value) {\n        if (value.IsString()) {\n            RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());\n            if (!r->IsValid()) {\n                r->~RegexType();\n                AllocatorType::Free(r);\n                r = 0;\n            }\n            return r;\n        }\n        return 0;\n    }\n\n    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {\n        return pattern->Search(str);\n    }\n#elif RAPIDJSON_SCHEMA_USE_STDREGEX\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType& value) {\n        if (value.IsString())\n            try {\n                return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);\n            }\n            catch (const std::regex_error&) {\n            }\n        return 0;\n    }\n\n    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {\n        std::match_results<const Ch*> r;\n        return std::regex_search(str, str + length, r, *pattern);\n    }\n#else\n    template <typename ValueType>\n    RegexType* CreatePattern(const ValueType&) { return 0; }\n\n    static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }\n#endif // RAPIDJSON_SCHEMA_USE_STDREGEX\n\n    void AddType(const ValueType& type) {\n        if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;\n        else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;\n        else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;\n        else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;\n        else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;\n        else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;\n        else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);\n    }\n\n    bool CreateParallelValidator(Context& context) const {\n        if (enum_ || context.arrayUniqueness)\n            context.hasher = context.factory.CreateHasher();\n\n        if (validatorCount_) {\n            RAPIDJSON_ASSERT(context.validators == 0);\n            context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));\n            context.validatorCount = validatorCount_;\n\n            if (allOf_.schemas)\n                CreateSchemaValidators(context, allOf_);\n\n            if (anyOf_.schemas)\n                CreateSchemaValidators(context, anyOf_);\n            \n            if (oneOf_.schemas)\n                CreateSchemaValidators(context, oneOf_);\n            \n            if (not_)\n                context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);\n            \n            if (hasSchemaDependencies_) {\n                for (SizeType i = 0; i < propertyCount_; i++)\n                    if (properties_[i].dependenciesSchema)\n                        context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);\n            }\n        }\n\n        return true;\n    }\n\n    void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {\n        for (SizeType i = 0; i < schemas.count; i++)\n            context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);\n    }\n\n    // O(n)\n    bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {\n        SizeType len = name.GetStringLength();\n        const Ch* str = name.GetString();\n        for (SizeType index = 0; index < propertyCount_; index++)\n            if (properties_[index].name.GetStringLength() == len && \n                (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))\n            {\n                *outIndex = index;\n                return true;\n            }\n        return false;\n    }\n\n    bool CheckInt(Context& context, int64_t i) const {\n        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        if (!minimum_.IsNull()) {\n            if (minimum_.IsInt64()) {\n                if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n            }\n            else if (minimum_.IsUint64()) {\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()\n            }\n            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!maximum_.IsNull()) {\n            if (maximum_.IsInt64()) {\n                if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n            }\n            else if (maximum_.IsUint64())\n                /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()\n            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!multipleOf_.IsNull()) {\n            if (multipleOf_.IsUint64()) {\n                if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n            }\n            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))\n                return false;\n        }\n\n        return true;\n    }\n\n    bool CheckUint(Context& context, uint64_t i) const {\n        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());\n\n        if (!minimum_.IsNull()) {\n            if (minimum_.IsUint64()) {\n                if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n            }\n            else if (minimum_.IsInt64())\n                /* do nothing */; // i >= 0 > minimum.Getint64()\n            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!maximum_.IsNull()) {\n            if (maximum_.IsUint64()) {\n                if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n            }\n            else if (maximum_.IsInt64())\n                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_\n            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))\n                return false;\n        }\n\n        if (!multipleOf_.IsNull()) {\n            if (multipleOf_.IsUint64()) {\n                if (i % multipleOf_.GetUint64() != 0)\n                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n            }\n            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))\n                return false;\n        }\n\n        return true;\n    }\n\n    bool CheckDoubleMinimum(Context& context, double d) const {\n        if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());\n        return true;\n    }\n\n    bool CheckDoubleMaximum(Context& context, double d) const {\n        if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());\n        return true;\n    }\n\n    bool CheckDoubleMultipleOf(Context& context, double d) const {\n        double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());\n        double q = std::floor(a / b);\n        double r = a - q * b;\n        if (r > 0.0)\n            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());\n        return true;\n    }\n\n    struct Property {\n        Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}\n        ~Property() { AllocatorType::Free(dependencies); }\n        SValue name;\n        const SchemaType* schema;\n        const SchemaType* dependenciesSchema;\n        SizeType dependenciesValidatorIndex;\n        bool* dependencies;\n        bool required;\n    };\n\n    struct PatternProperty {\n        PatternProperty() : schema(), pattern() {}\n        ~PatternProperty() { \n            if (pattern) {\n                pattern->~RegexType();\n                AllocatorType::Free(pattern);\n            }\n        }\n        const SchemaType* schema;\n        RegexType* pattern;\n    };\n\n    AllocatorType* allocator_;\n    uint64_t* enum_;\n    SizeType enumCount_;\n    SchemaArray allOf_;\n    SchemaArray anyOf_;\n    SchemaArray oneOf_;\n    const SchemaType* not_;\n    unsigned type_; // bitmask of kSchemaType\n    SizeType validatorCount_;\n    SizeType notValidatorIndex_;\n\n    Property* properties_;\n    const SchemaType* additionalPropertiesSchema_;\n    PatternProperty* patternProperties_;\n    SizeType patternPropertyCount_;\n    SizeType propertyCount_;\n    SizeType minProperties_;\n    SizeType maxProperties_;\n    bool additionalProperties_;\n    bool hasDependencies_;\n    bool hasRequired_;\n    bool hasSchemaDependencies_;\n\n    const SchemaType* additionalItemsSchema_;\n    const SchemaType* itemsList_;\n    const SchemaType** itemsTuple_;\n    SizeType itemsTupleCount_;\n    SizeType minItems_;\n    SizeType maxItems_;\n    bool additionalItems_;\n    bool uniqueItems_;\n\n    RegexType* pattern_;\n    SizeType minLength_;\n    SizeType maxLength_;\n\n    SValue minimum_;\n    SValue maximum_;\n    SValue multipleOf_;\n    bool exclusiveMinimum_;\n    bool exclusiveMaximum_;\n};\n\ntemplate<typename Stack, typename Ch>\nstruct TokenHelper {\n    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {\n        *documentStack.template Push<Ch>() = '/';\n        char buffer[21];\n        size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);\n        for (size_t i = 0; i < length; i++)\n            *documentStack.template Push<Ch>() = buffer[i];\n    }\n};\n\n// Partial specialized version for char to prevent buffer copying.\ntemplate <typename Stack>\nstruct TokenHelper<Stack, char> {\n    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {\n        if (sizeof(SizeType) == 4) {\n            char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint\n            *buffer++ = '/';\n            const char* end = internal::u32toa(index, buffer);\n             documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));\n        }\n        else {\n            char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64\n            *buffer++ = '/';\n            const char* end = internal::u64toa(index, buffer);\n            documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));\n        }\n    }\n};\n\n} // namespace internal\n\n///////////////////////////////////////////////////////////////////////////////\n// IGenericRemoteSchemaDocumentProvider\n\ntemplate <typename SchemaDocumentType>\nclass IGenericRemoteSchemaDocumentProvider {\npublic:\n    typedef typename SchemaDocumentType::Ch Ch;\n\n    virtual ~IGenericRemoteSchemaDocumentProvider() {}\n    virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;\n};\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericSchemaDocument\n\n//! JSON schema document.\n/*!\n    A JSON schema document is a compiled version of a JSON schema.\n    It is basically a tree of internal::Schema.\n\n    \\note This is an immutable class (i.e. its instance cannot be modified after construction).\n    \\tparam ValueT Type of JSON value (e.g. \\c Value ), which also determine the encoding.\n    \\tparam Allocator Allocator type for allocating memory of this document.\n*/\ntemplate <typename ValueT, typename Allocator = CrtAllocator>\nclass GenericSchemaDocument {\npublic:\n    typedef ValueT ValueType;\n    typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;\n    typedef Allocator AllocatorType;\n    typedef typename ValueType::EncodingType EncodingType;\n    typedef typename EncodingType::Ch Ch;\n    typedef internal::Schema<GenericSchemaDocument> SchemaType;\n    typedef GenericPointer<ValueType, Allocator> PointerType;\n    friend class internal::Schema<GenericSchemaDocument>;\n    template <typename, typename, typename>\n    friend class GenericSchemaValidator;\n\n    //! Constructor.\n    /*!\n        Compile a JSON document into schema document.\n\n        \\param document A JSON document as source.\n        \\param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.\n        \\param allocator An optional allocator instance for allocating memory. Can be null.\n    */\n    explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :\n        remoteProvider_(remoteProvider),\n        allocator_(allocator),\n        ownAllocator_(),\n        root_(),\n        schemaMap_(allocator, kInitialSchemaMapSize),\n        schemaRef_(allocator, kInitialSchemaRefSize)\n    {\n        if (!allocator_)\n            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());\n\n        // Generate root schema, it will call CreateSchema() to create sub-schemas,\n        // And call AddRefSchema() if there are $ref.\n        CreateSchemaRecursive(&root_, PointerType(), document, document);\n\n        // Resolve $ref\n        while (!schemaRef_.Empty()) {\n            SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);\n            if (const SchemaType* s = GetSchema(refEntry->target)) {\n                if (refEntry->schema)\n                    *refEntry->schema = s;\n\n                // Create entry in map if not exist\n                if (!GetSchema(refEntry->source)) {\n                    new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);\n                }\n            }\n            refEntry->~SchemaRefEntry();\n        }\n\n        RAPIDJSON_ASSERT(root_ != 0);\n\n        schemaRef_.ShrinkToFit(); // Deallocate all memory for ref\n    }\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    //! Move constructor in C++11\n    GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :\n        remoteProvider_(rhs.remoteProvider_),\n        allocator_(rhs.allocator_),\n        ownAllocator_(rhs.ownAllocator_),\n        root_(rhs.root_),\n        schemaMap_(std::move(rhs.schemaMap_)),\n        schemaRef_(std::move(rhs.schemaRef_))\n    {\n        rhs.remoteProvider_ = 0;\n        rhs.allocator_ = 0;\n        rhs.ownAllocator_ = 0;\n    }\n#endif\n\n    //! Destructor\n    ~GenericSchemaDocument() {\n        while (!schemaMap_.Empty())\n            schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();\n\n        RAPIDJSON_DELETE(ownAllocator_);\n    }\n\n    //! Get the root schema.\n    const SchemaType& GetRoot() const { return *root_; }\n\nprivate:\n    //! Prohibit copying\n    GenericSchemaDocument(const GenericSchemaDocument&);\n    //! Prohibit assignment\n    GenericSchemaDocument& operator=(const GenericSchemaDocument&);\n\n    struct SchemaRefEntry {\n        SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}\n        PointerType source;\n        PointerType target;\n        const SchemaType** schema;\n    };\n\n    struct SchemaEntry {\n        SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}\n        ~SchemaEntry() {\n            if (owned) {\n                schema->~SchemaType();\n                Allocator::Free(schema);\n            }\n        }\n        PointerType pointer;\n        SchemaType* schema;\n        bool owned;\n    };\n\n    void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {\n        if (schema)\n            *schema = SchemaType::GetTypeless();\n\n        if (v.GetType() == kObjectType) {\n            const SchemaType* s = GetSchema(pointer);\n            if (!s)\n                CreateSchema(schema, pointer, v, document);\n\n            for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)\n                CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);\n        }\n        else if (v.GetType() == kArrayType)\n            for (SizeType i = 0; i < v.Size(); i++)\n                CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);\n    }\n\n    void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {\n        RAPIDJSON_ASSERT(pointer.IsValid());\n        if (v.IsObject()) {\n            if (!HandleRefSchema(pointer, schema, v, document)) {\n                SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);\n                new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);\n                if (schema)\n                    *schema = s;\n            }\n        }\n    }\n\n    bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {\n        static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\\0' };\n        static const ValueType kRefValue(kRefString, 4);\n\n        typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);\n        if (itr == v.MemberEnd())\n            return false;\n\n        if (itr->value.IsString()) {\n            SizeType len = itr->value.GetStringLength();\n            if (len > 0) {\n                const Ch* s = itr->value.GetString();\n                SizeType i = 0;\n                while (i < len && s[i] != '#') // Find the first #\n                    i++;\n\n                if (i > 0) { // Remote reference, resolve immediately\n                    if (remoteProvider_) {\n                        if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {\n                            PointerType pointer(&s[i], len - i, allocator_);\n                            if (pointer.IsValid()) {\n                                if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {\n                                    if (schema)\n                                        *schema = sc;\n                                    return true;\n                                }\n                            }\n                        }\n                    }\n                }\n                else if (s[i] == '#') { // Local reference, defer resolution\n                    PointerType pointer(&s[i], len - i, allocator_);\n                    if (pointer.IsValid()) {\n                        if (const ValueType* nv = pointer.Get(document))\n                            if (HandleRefSchema(source, schema, *nv, document))\n                                return true;\n\n                        new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);\n                        return true;\n                    }\n                }\n            }\n        }\n        return false;\n    }\n\n    const SchemaType* GetSchema(const PointerType& pointer) const {\n        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)\n            if (pointer == target->pointer)\n                return target->schema;\n        return 0;\n    }\n\n    PointerType GetPointer(const SchemaType* schema) const {\n        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)\n            if (schema == target->schema)\n                return target->pointer;\n        return PointerType();\n    }\n\n    static const size_t kInitialSchemaMapSize = 64;\n    static const size_t kInitialSchemaRefSize = 64;\n\n    IRemoteSchemaDocumentProviderType* remoteProvider_;\n    Allocator *allocator_;\n    Allocator *ownAllocator_;\n    const SchemaType* root_;                //!< Root schema.\n    internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas\n    internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref\n};\n\n//! GenericSchemaDocument using Value type.\ntypedef GenericSchemaDocument<Value> SchemaDocument;\n//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.\ntypedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;\n\n///////////////////////////////////////////////////////////////////////////////\n// GenericSchemaValidator\n\n//! JSON Schema Validator.\n/*!\n    A SAX style JSON schema validator.\n    It uses a \\c GenericSchemaDocument to validate SAX events.\n    It delegates the incoming SAX events to an output handler.\n    The default output handler does nothing.\n    It can be reused multiple times by calling \\c Reset().\n\n    \\tparam SchemaDocumentType Type of schema document.\n    \\tparam OutputHandler Type of output handler. Default handler does nothing.\n    \\tparam StateAllocator Allocator for storing the internal validation states.\n*/\ntemplate <\n    typename SchemaDocumentType,\n    typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,\n    typename StateAllocator = CrtAllocator>\nclass GenericSchemaValidator :\n    public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, \n    public internal::ISchemaValidator\n{\npublic:\n    typedef typename SchemaDocumentType::SchemaType SchemaType;\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename SchemaType::EncodingType EncodingType;\n    typedef typename EncodingType::Ch Ch;\n\n    //! Constructor without output handler.\n    /*!\n        \\param schemaDocument The schema document to conform to.\n        \\param allocator Optional allocator for storing internal validation states.\n        \\param schemaStackCapacity Optional initial capacity of schema path stack.\n        \\param documentStackCapacity Optional initial capacity of document path stack.\n    */\n    GenericSchemaValidator(\n        const SchemaDocumentType& schemaDocument,\n        StateAllocator* allocator = 0, \n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(schemaDocument.GetRoot()),\n        outputHandler_(GetNullHandler()),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(0)\n#endif\n    {\n    }\n\n    //! Constructor with output handler.\n    /*!\n        \\param schemaDocument The schema document to conform to.\n        \\param allocator Optional allocator for storing internal validation states.\n        \\param schemaStackCapacity Optional initial capacity of schema path stack.\n        \\param documentStackCapacity Optional initial capacity of document path stack.\n    */\n    GenericSchemaValidator(\n        const SchemaDocumentType& schemaDocument,\n        OutputHandler& outputHandler,\n        StateAllocator* allocator = 0, \n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(schemaDocument.GetRoot()),\n        outputHandler_(outputHandler),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(0)\n#endif\n    {\n    }\n\n    //! Destructor.\n    ~GenericSchemaValidator() {\n        Reset();\n        RAPIDJSON_DELETE(ownStateAllocator_);\n    }\n\n    //! Reset the internal states.\n    void Reset() {\n        while (!schemaStack_.Empty())\n            PopSchema();\n        documentStack_.Clear();\n        valid_ = true;\n    }\n\n    //! Checks whether the current state is valid.\n    // Implementation of ISchemaValidator\n    virtual bool IsValid() const { return valid_; }\n\n    //! Gets the JSON pointer pointed to the invalid schema.\n    PointerType GetInvalidSchemaPointer() const {\n        return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());\n    }\n\n    //! Gets the keyword of invalid schema.\n    const Ch* GetInvalidSchemaKeyword() const {\n        return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;\n    }\n\n    //! Gets the JSON pointer pointed to the invalid value.\n    PointerType GetInvalidDocumentPointer() const {\n        return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));\n    }\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \\\nRAPIDJSON_MULTILINEMACRO_BEGIN\\\n    *documentStack_.template Push<Ch>() = '\\0';\\\n    documentStack_.template Pop<Ch>(1);\\\n    internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\\\nRAPIDJSON_MULTILINEMACRO_END\n#else\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()\n#endif\n\n#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\\\n    if (!valid_) return false; \\\n    if (!BeginValue() || !CurrentSchema().method arg1) {\\\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\\\n        return valid_ = false;\\\n    }\n\n#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\\\n    for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\\\n        if (context->hasher)\\\n            static_cast<HasherType*>(context->hasher)->method arg2;\\\n        if (context->validators)\\\n            for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\\\n                static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\\\n        if (context->patternPropertiesValidators)\\\n            for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\\\n                static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\\\n    }\n\n#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\\\n    return valid_ = EndValue() && outputHandler_.method arg2\n\n#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \\\n    RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\\\n    RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\\\n    RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)\n\n    bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()   ), ( )); }\n    bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }\n    bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }\n    bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }\n    bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }\n    bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }\n    bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }\n    bool RawNumber(const Ch* str, SizeType length, bool copy)\n                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }\n    bool String(const Ch* str, SizeType length, bool copy)\n                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }\n\n    bool StartObject() {\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());\n        return valid_ = outputHandler_.StartObject();\n    }\n    \n    bool Key(const Ch* str, SizeType len, bool copy) {\n        if (!valid_) return false;\n        AppendToken(str, len);\n        if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));\n        return valid_ = outputHandler_.Key(str, len, copy);\n    }\n    \n    bool EndObject(SizeType memberCount) { \n        if (!valid_) return false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));\n        if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));\n    }\n\n    bool StartArray() {\n        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());\n        return valid_ = outputHandler_.StartArray();\n    }\n    \n    bool EndArray(SizeType elementCount) {\n        if (!valid_) return false;\n        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));\n        if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;\n        RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));\n    }\n\n#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_\n#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_\n#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_\n#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_\n\n    // Implementation of ISchemaStateFactory<SchemaType>\n    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {\n        return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,\n#if RAPIDJSON_SCHEMA_VERBOSE\n        depth_ + 1,\n#endif\n        &GetStateAllocator());\n    }\n\n    virtual void DestroySchemaValidator(ISchemaValidator* validator) {\n        GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);\n        v->~GenericSchemaValidator();\n        StateAllocator::Free(v);\n    }\n\n    virtual void* CreateHasher() {\n        return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());\n    }\n\n    virtual uint64_t GetHashCode(void* hasher) {\n        return static_cast<HasherType*>(hasher)->GetHashCode();\n    }\n\n    virtual void DestroryHasher(void* hasher) {\n        HasherType* h = static_cast<HasherType*>(hasher);\n        h->~HasherType();\n        StateAllocator::Free(h);\n    }\n\n    virtual void* MallocState(size_t size) {\n        return GetStateAllocator().Malloc(size);\n    }\n\n    virtual void FreeState(void* p) {\n        return StateAllocator::Free(p);\n    }\n\nprivate:\n    typedef typename SchemaType::Context Context;\n    typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;\n    typedef internal::Hasher<EncodingType, StateAllocator> HasherType;\n\n    GenericSchemaValidator( \n        const SchemaDocumentType& schemaDocument,\n        const SchemaType& root,\n#if RAPIDJSON_SCHEMA_VERBOSE\n        unsigned depth,\n#endif\n        StateAllocator* allocator = 0,\n        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,\n        size_t documentStackCapacity = kDefaultDocumentStackCapacity)\n        :\n        schemaDocument_(&schemaDocument),\n        root_(root),\n        outputHandler_(GetNullHandler()),\n        stateAllocator_(allocator),\n        ownStateAllocator_(0),\n        schemaStack_(allocator, schemaStackCapacity),\n        documentStack_(allocator, documentStackCapacity),\n        valid_(true)\n#if RAPIDJSON_SCHEMA_VERBOSE\n        , depth_(depth)\n#endif\n    {\n    }\n\n    StateAllocator& GetStateAllocator() {\n        if (!stateAllocator_)\n            stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());\n        return *stateAllocator_;\n    }\n\n    bool BeginValue() {\n        if (schemaStack_.Empty())\n            PushSchema(root_);\n        else {\n            if (CurrentContext().inArray)\n                internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);\n\n            if (!CurrentSchema().BeginValue(CurrentContext()))\n                return false;\n\n            SizeType count = CurrentContext().patternPropertiesSchemaCount;\n            const SchemaType** sa = CurrentContext().patternPropertiesSchemas;\n            typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;\n            bool valueUniqueness = CurrentContext().valueUniqueness;\n            if (CurrentContext().valueSchema)\n                PushSchema(*CurrentContext().valueSchema);\n\n            if (count > 0) {\n                CurrentContext().objectPatternValidatorType = patternValidatorType;\n                ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;\n                SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;\n                va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));\n                for (SizeType i = 0; i < count; i++)\n                    va[validatorCount++] = CreateSchemaValidator(*sa[i]);\n            }\n\n            CurrentContext().arrayUniqueness = valueUniqueness;\n        }\n        return true;\n    }\n\n    bool EndValue() {\n        if (!CurrentSchema().EndValue(CurrentContext()))\n            return false;\n\n#if RAPIDJSON_SCHEMA_VERBOSE\n        GenericStringBuffer<EncodingType> sb;\n        schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);\n\n        *documentStack_.template Push<Ch>() = '\\0';\n        documentStack_.template Pop<Ch>(1);\n        internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());\n#endif\n\n        uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;\n        \n        PopSchema();\n\n        if (!schemaStack_.Empty()) {\n            Context& context = CurrentContext();\n            if (context.valueUniqueness) {\n                HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);\n                if (!a)\n                    CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);\n                for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)\n                    if (itr->GetUint64() == h)\n                        RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());\n                a->PushBack(h, GetStateAllocator());\n            }\n        }\n\n        // Remove the last token of document pointer\n        while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')\n            ;\n\n        return true;\n    }\n\n    void AppendToken(const Ch* str, SizeType len) {\n        documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters\n        *documentStack_.template PushUnsafe<Ch>() = '/';\n        for (SizeType i = 0; i < len; i++) {\n            if (str[i] == '~') {\n                *documentStack_.template PushUnsafe<Ch>() = '~';\n                *documentStack_.template PushUnsafe<Ch>() = '0';\n            }\n            else if (str[i] == '/') {\n                *documentStack_.template PushUnsafe<Ch>() = '~';\n                *documentStack_.template PushUnsafe<Ch>() = '1';\n            }\n            else\n                *documentStack_.template PushUnsafe<Ch>() = str[i];\n        }\n    }\n\n    RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }\n    \n    RAPIDJSON_FORCEINLINE void PopSchema() {\n        Context* c = schemaStack_.template Pop<Context>(1);\n        if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {\n            a->~HashCodeArray();\n            StateAllocator::Free(a);\n        }\n        c->~Context();\n    }\n\n    const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }\n    Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }\n    const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }\n\n    static OutputHandler& GetNullHandler() {\n        static OutputHandler nullHandler;\n        return nullHandler;\n    }\n\n    static const size_t kDefaultSchemaStackCapacity = 1024;\n    static const size_t kDefaultDocumentStackCapacity = 256;\n    const SchemaDocumentType* schemaDocument_;\n    const SchemaType& root_;\n    OutputHandler& outputHandler_;\n    StateAllocator* stateAllocator_;\n    StateAllocator* ownStateAllocator_;\n    internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)\n    internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)\n    bool valid_;\n#if RAPIDJSON_SCHEMA_VERBOSE\n    unsigned depth_;\n#endif\n};\n\ntypedef GenericSchemaValidator<SchemaDocument> SchemaValidator;\n\n///////////////////////////////////////////////////////////////////////////////\n// SchemaValidatingReader\n\n//! A helper class for parsing with validation.\n/*!\n    This helper class is a functor, designed as a parameter of \\ref GenericDocument::Populate().\n\n    \\tparam parseFlags Combination of \\ref ParseFlag.\n    \\tparam InputStream Type of input stream, implementing Stream concept.\n    \\tparam SourceEncoding Encoding of the input stream.\n    \\tparam SchemaDocumentType Type of schema document.\n    \\tparam StackAllocator Allocator type for stack.\n*/\ntemplate <\n    unsigned parseFlags,\n    typename InputStream,\n    typename SourceEncoding,\n    typename SchemaDocumentType = SchemaDocument,\n    typename StackAllocator = CrtAllocator>\nclass SchemaValidatingReader {\npublic:\n    typedef typename SchemaDocumentType::PointerType PointerType;\n    typedef typename InputStream::Ch Ch;\n\n    //! Constructor\n    /*!\n        \\param is Input stream.\n        \\param sd Schema document.\n    */\n    SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}\n\n    template <typename Handler>\n    bool operator()(Handler& handler) {\n        GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;\n        GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);\n        parseResult_ = reader.template Parse<parseFlags>(is_, validator);\n\n        isValid_ = validator.IsValid();\n        if (isValid_) {\n            invalidSchemaPointer_ = PointerType();\n            invalidSchemaKeyword_ = 0;\n            invalidDocumentPointer_ = PointerType();\n        }\n        else {\n            invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();\n            invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();\n            invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();\n        }\n\n        return parseResult_;\n    }\n\n    const ParseResult& GetParseResult() const { return parseResult_; }\n    bool IsValid() const { return isValid_; }\n    const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }\n    const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }\n    const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }\n\nprivate:\n    InputStream& is_;\n    const SchemaDocumentType& sd_;\n\n    ParseResult parseResult_;\n    PointerType invalidSchemaPointer_;\n    const Ch* invalidSchemaKeyword_;\n    PointerType invalidDocumentPointer_;\n    bool isValid_;\n};\n\nRAPIDJSON_NAMESPACE_END\nRAPIDJSON_DIAG_POP\n\n#endif // RAPIDJSON_SCHEMA_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/stream.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#include \"rapidjson.h\"\n\n#ifndef RAPIDJSON_STREAM_H_\n#define RAPIDJSON_STREAM_H_\n\n#include \"encodings.h\"\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n//  Stream\n\n/*! \\class rapidjson::Stream\n    \\brief Concept for reading and writing characters.\n\n    For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().\n\n    For write-only stream, only need to implement Put() and Flush().\n\n\\code\nconcept Stream {\n    typename Ch;    //!< Character type of the stream.\n\n    //! Read the current character from stream without moving the read cursor.\n    Ch Peek() const;\n\n    //! Read the current character from stream and moving the read cursor to next character.\n    Ch Take();\n\n    //! Get the current read cursor.\n    //! \\return Number of characters read from start.\n    size_t Tell();\n\n    //! Begin writing operation at the current read pointer.\n    //! \\return The begin writer pointer.\n    Ch* PutBegin();\n\n    //! Write a character.\n    void Put(Ch c);\n\n    //! Flush the buffer.\n    void Flush();\n\n    //! End the writing operation.\n    //! \\param begin The begin write pointer returned by PutBegin().\n    //! \\return Number of characters written.\n    size_t PutEnd(Ch* begin);\n}\n\\endcode\n*/\n\n//! Provides additional information for stream.\n/*!\n    By using traits pattern, this type provides a default configuration for stream.\n    For custom stream, this type can be specialized for other configuration.\n    See TEST(Reader, CustomStringStream) in readertest.cpp for example.\n*/\ntemplate<typename Stream>\nstruct StreamTraits {\n    //! Whether to make local copy of stream for optimization during parsing.\n    /*!\n        By default, for safety, streams do not use local copy optimization.\n        Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.\n    */\n    enum { copyOptimization = 0 };\n};\n\n//! Reserve n characters for writing to a stream.\ntemplate<typename Stream>\ninline void PutReserve(Stream& stream, size_t count) {\n    (void)stream;\n    (void)count;\n}\n\n//! Write character to a stream, presuming buffer is reserved.\ntemplate<typename Stream>\ninline void PutUnsafe(Stream& stream, typename Stream::Ch c) {\n    stream.Put(c);\n}\n\n//! Put N copies of a character to a stream.\ntemplate<typename Stream, typename Ch>\ninline void PutN(Stream& stream, Ch c, size_t n) {\n    PutReserve(stream, n);\n    for (size_t i = 0; i < n; i++)\n        PutUnsafe(stream, c);\n}\n\n///////////////////////////////////////////////////////////////////////////////\n// StringStream\n\n//! Read-only string stream.\n/*! \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringStream(const Ch *src) : src_(src), head_(src) {}\n\n    Ch Peek() const { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() const { return static_cast<size_t>(src_ - head_); }\n\n    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }\n    void Put(Ch) { RAPIDJSON_ASSERT(false); }\n    void Flush() { RAPIDJSON_ASSERT(false); }\n    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }\n\n    const Ch* src_;     //!< Current read position.\n    const Ch* head_;    //!< Original head of the string.\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! String stream with UTF8 encoding.\ntypedef GenericStringStream<UTF8<> > StringStream;\n\n///////////////////////////////////////////////////////////////////////////////\n// InsituStringStream\n\n//! A read-write string stream.\n/*! This string stream is particularly designed for in-situ parsing.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding>\nstruct GenericInsituStringStream {\n    typedef typename Encoding::Ch Ch;\n\n    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}\n\n    // Read\n    Ch Peek() { return *src_; }\n    Ch Take() { return *src_++; }\n    size_t Tell() { return static_cast<size_t>(src_ - head_); }\n\n    // Write\n    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }\n\n    Ch* PutBegin() { return dst_ = src_; }\n    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }\n    void Flush() {}\n\n    Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }\n    void Pop(size_t count) { dst_ -= count; }\n\n    Ch* src_;\n    Ch* dst_;\n    Ch* head_;\n};\n\ntemplate <typename Encoding>\nstruct StreamTraits<GenericInsituStringStream<Encoding> > {\n    enum { copyOptimization = 1 };\n};\n\n//! Insitu string stream with UTF8 encoding.\ntypedef GenericInsituStringStream<UTF8<> > InsituStringStream;\n\nRAPIDJSON_NAMESPACE_END\n\n#endif // RAPIDJSON_STREAM_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/stringbuffer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_STRINGBUFFER_H_\n#define RAPIDJSON_STRINGBUFFER_H_\n\n#include \"stream.h\"\n#include \"internal/stack.h\"\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n#include <utility> // std::move\n#endif\n\n#include \"internal/stack.h\"\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(c++98-compat)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n//! Represents an in-memory output stream.\n/*!\n    \\tparam Encoding Encoding of the stream.\n    \\tparam Allocator type for allocating memory buffer.\n    \\note implements Stream concept\n*/\ntemplate <typename Encoding, typename Allocator = CrtAllocator>\nclass GenericStringBuffer {\npublic:\n    typedef typename Encoding::Ch Ch;\n\n    GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}\n\n#if RAPIDJSON_HAS_CXX11_RVALUE_REFS\n    GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}\n    GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {\n        if (&rhs != this)\n            stack_ = std::move(rhs.stack_);\n        return *this;\n    }\n#endif\n\n    void Put(Ch c) { *stack_.template Push<Ch>() = c; }\n    void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }\n    void Flush() {}\n\n    void Clear() { stack_.Clear(); }\n    void ShrinkToFit() {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.ShrinkToFit();\n        stack_.template Pop<Ch>(1);\n    }\n\n    void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }\n    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }\n    Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }\n    void Pop(size_t count) { stack_.template Pop<Ch>(count); }\n\n    const Ch* GetString() const {\n        // Push and pop a null terminator. This is safe.\n        *stack_.template Push<Ch>() = '\\0';\n        stack_.template Pop<Ch>(1);\n\n        return stack_.template Bottom<Ch>();\n    }\n\n    size_t GetSize() const { return stack_.GetSize(); }\n\n    static const size_t kDefaultCapacity = 256;\n    mutable internal::Stack<Allocator> stack_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    GenericStringBuffer(const GenericStringBuffer&);\n    GenericStringBuffer& operator=(const GenericStringBuffer&);\n};\n\n//! String buffer with UTF8 encoding\ntypedef GenericStringBuffer<UTF8<> > StringBuffer;\n\ntemplate<typename Encoding, typename Allocator>\ninline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {\n    stream.Reserve(count);\n}\n\ntemplate<typename Encoding, typename Allocator>\ninline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {\n    stream.PutUnsafe(c);\n}\n\n//! Implement specialized version of PutN() with memset() for better performance.\ntemplate<>\ninline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {\n    std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));\n}\n\nRAPIDJSON_NAMESPACE_END\n\n#if defined(__clang__)\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_STRINGBUFFER_H_\n"
  },
  {
    "path": "src/thirdparty/rapidjson/writer.h",
    "content": "// Tencent is pleased to support the open source community by making RapidJSON available.\n// \n// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.\n//\n// Licensed under the MIT License (the \"License\"); you may not use this file except\n// in compliance with the License. You may obtain a copy of the License at\n//\n// http://opensource.org/licenses/MIT\n//\n// Unless required by applicable law or agreed to in writing, software distributed \n// under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR \n// CONDITIONS OF ANY KIND, either express or implied. See the License for the \n// specific language governing permissions and limitations under the License.\n\n#ifndef RAPIDJSON_WRITER_H_\n#define RAPIDJSON_WRITER_H_\n\n#include \"stream.h\"\n#include \"internal/stack.h\"\n#include \"internal/strfunc.h\"\n#include \"internal/dtoa.h\"\n#include \"internal/itoa.h\"\n#include \"stringbuffer.h\"\n#include <new>      // placement new\n\n#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)\n#include <intrin.h>\n#pragma intrinsic(_BitScanForward)\n#endif\n#ifdef RAPIDJSON_SSE42\n#include <nmmintrin.h>\n#elif defined(RAPIDJSON_SSE2)\n#include <emmintrin.h>\n#endif\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(4127) // conditional expression is constant\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_PUSH\nRAPIDJSON_DIAG_OFF(padded)\nRAPIDJSON_DIAG_OFF(unreachable-code)\n#endif\n\nRAPIDJSON_NAMESPACE_BEGIN\n\n///////////////////////////////////////////////////////////////////////////////\n// WriteFlag\n\n/*! \\def RAPIDJSON_WRITE_DEFAULT_FLAGS \n    \\ingroup RAPIDJSON_CONFIG\n    \\brief User-defined kWriteDefaultFlags definition.\n\n    User can define this as any \\c WriteFlag combinations.\n*/\n#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS\n#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags\n#endif\n\n//! Combination of writeFlags\nenum WriteFlag {\n    kWriteNoFlags = 0,              //!< No flags are set.\n    kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.\n    kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN.\n    kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS\n};\n\n//! JSON writer\n/*! Writer implements the concept Handler.\n    It generates JSON text by events to an output os.\n\n    User may programmatically calls the functions of a writer to generate JSON text.\n\n    On the other side, a writer can also be passed to objects that generates events, \n\n    for example Reader::Parse() and Document::Accept().\n\n    \\tparam OutputStream Type of output stream.\n    \\tparam SourceEncoding Encoding of source string.\n    \\tparam TargetEncoding Encoding of output stream.\n    \\tparam StackAllocator Type of allocator for allocating memory of stack.\n    \\note implements Handler concept\n*/\ntemplate<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>\nclass Writer {\npublic:\n    typedef typename SourceEncoding::Ch Ch;\n\n    static const int kDefaultMaxDecimalPlaces = 324;\n\n    //! Constructor\n    /*! \\param os Output stream.\n        \\param stackAllocator User supplied allocator. If it is null, it will create a private one.\n        \\param levelDepth Initial capacity of stack.\n    */\n    explicit\n    Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : \n        os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}\n\n    explicit\n    Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :\n        os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}\n\n    //! Reset the writer with a new stream.\n    /*!\n        This function reset the writer with a new stream and default settings,\n        in order to make a Writer object reusable for output multiple JSONs.\n\n        \\param os New output stream.\n        \\code\n        Writer<OutputStream> writer(os1);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n\n        writer.Reset(os2);\n        writer.StartObject();\n        // ...\n        writer.EndObject();\n        \\endcode\n    */\n    void Reset(OutputStream& os) {\n        os_ = &os;\n        hasRoot_ = false;\n        level_stack_.Clear();\n    }\n\n    //! Checks whether the output is a complete JSON.\n    /*!\n        A complete JSON has a complete root object or array.\n    */\n    bool IsComplete() const {\n        return hasRoot_ && level_stack_.Empty();\n    }\n\n    int GetMaxDecimalPlaces() const {\n        return maxDecimalPlaces_;\n    }\n\n    //! Sets the maximum number of decimal places for double output.\n    /*!\n        This setting truncates the output with specified number of decimal places.\n\n        For example, \n\n        \\code\n        writer.SetMaxDecimalPlaces(3);\n        writer.StartArray();\n        writer.Double(0.12345);                 // \"0.123\"\n        writer.Double(0.0001);                  // \"0.0\"\n        writer.Double(1.234567890123456e30);    // \"1.234567890123456e30\" (do not truncate significand for positive exponent)\n        writer.Double(1.23e-4);                 // \"0.0\"                  (do truncate significand for negative exponent)\n        writer.EndArray();\n        \\endcode\n\n        The default setting does not truncate any decimal places. You can restore to this setting by calling\n        \\code\n        writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);\n        \\endcode\n    */\n    void SetMaxDecimalPlaces(int maxDecimalPlaces) {\n        maxDecimalPlaces_ = maxDecimalPlaces;\n    }\n\n    /*!@name Implementation of Handler\n        \\see Handler\n    */\n    //@{\n\n    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }\n    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }\n    bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }\n    bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }\n    bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }\n    bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }\n\n    //! Writes the given \\c double value to the stream\n    /*!\n        \\param d The value to be written.\n        \\return Whether it is succeed.\n    */\n    bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); }\n\n    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        Prefix(kNumberType);\n        return EndValue(WriteString(str, length));\n    }\n\n    bool String(const Ch* str, SizeType length, bool copy = false) {\n        (void)copy;\n        Prefix(kStringType);\n        return EndValue(WriteString(str, length));\n    }\n\n#if RAPIDJSON_HAS_STDSTRING\n    bool String(const std::basic_string<Ch>& str) {\n        return String(str.data(), SizeType(str.size()));\n    }\n#endif\n\n    bool StartObject() {\n        Prefix(kObjectType);\n        new (level_stack_.template Push<Level>()) Level(false);\n        return WriteStartObject();\n    }\n\n    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }\n\n    bool EndObject(SizeType memberCount = 0) {\n        (void)memberCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);\n        level_stack_.template Pop<Level>(1);\n        return EndValue(WriteEndObject());\n    }\n\n    bool StartArray() {\n        Prefix(kArrayType);\n        new (level_stack_.template Push<Level>()) Level(true);\n        return WriteStartArray();\n    }\n\n    bool EndArray(SizeType elementCount = 0) {\n        (void)elementCount;\n        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));\n        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);\n        level_stack_.template Pop<Level>(1);\n        return EndValue(WriteEndArray());\n    }\n    //@}\n\n    /*! @name Convenience extensions */\n    //@{\n\n    //! Simpler but slower overload.\n    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }\n    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }\n\n    //@}\n\n    //! Write a raw JSON value.\n    /*!\n        For user to write a stringified JSON as a value.\n\n        \\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.\n        \\param length Length of the json.\n        \\param type Type of the root of json.\n    */\n    bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }\n\nprotected:\n    //! Information for each nested level\n    struct Level {\n        Level(bool inArray_) : valueCount(0), inArray(inArray_) {}\n        size_t valueCount;  //!< number of values in this level\n        bool inArray;       //!< true if in array, otherwise in object\n    };\n\n    static const size_t kDefaultLevelDepth = 32;\n\n    bool WriteNull()  {\n        PutReserve(*os_, 4);\n        PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;\n    }\n\n    bool WriteBool(bool b)  {\n        if (b) {\n            PutReserve(*os_, 4);\n            PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');\n        }\n        else {\n            PutReserve(*os_, 5);\n            PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');\n        }\n        return true;\n    }\n\n    bool WriteInt(int i) {\n        char buffer[11];\n        const char* end = internal::i32toa(i, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));\n        return true;\n    }\n\n    bool WriteUint(unsigned u) {\n        char buffer[10];\n        const char* end = internal::u32toa(u, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));\n        return true;\n    }\n\n    bool WriteInt64(int64_t i64) {\n        char buffer[21];\n        const char* end = internal::i64toa(i64, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (const char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));\n        return true;\n    }\n\n    bool WriteUint64(uint64_t u64) {\n        char buffer[20];\n        char* end = internal::u64toa(u64, buffer);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));\n        return true;\n    }\n\n    bool WriteDouble(double d) {\n        if (internal::Double(d).IsNanOrInf()) {\n            if (!(writeFlags & kWriteNanAndInfFlag))\n                return false;\n            if (internal::Double(d).IsNan()) {\n                PutReserve(*os_, 3);\n                PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');\n                return true;\n            }\n            if (internal::Double(d).Sign()) {\n                PutReserve(*os_, 9);\n                PutUnsafe(*os_, '-');\n            }\n            else\n                PutReserve(*os_, 8);\n            PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');\n            PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');\n            return true;\n        }\n\n        char buffer[25];\n        char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);\n        PutReserve(*os_, static_cast<size_t>(end - buffer));\n        for (char* p = buffer; p != end; ++p)\n            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));\n        return true;\n    }\n\n    bool WriteString(const Ch* str, SizeType length)  {\n        static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };\n        static const char escape[256] = {\n#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0\n            //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00\n            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10\n              0,   0, '\"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20\n            Z16, Z16,                                                                       // 30~4F\n              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\\\',   0,   0,   0, // 50\n            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF\n#undef Z16\n        };\n\n        if (TargetEncoding::supportUnicode)\n            PutReserve(*os_, 2 + length * 6); // \"\\uxxxx...\"\n        else\n            PutReserve(*os_, 2 + length * 12);  // \"\\uxxxx\\uyyyy...\"\n\n        PutUnsafe(*os_, '\\\"');\n        GenericStringStream<SourceEncoding> is(str);\n        while (ScanWriteUnescapedString(is, length)) {\n            const Ch c = is.Peek();\n            if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {\n                // Unicode escaping\n                unsigned codepoint;\n                if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))\n                    return false;\n                PutUnsafe(*os_, '\\\\');\n                PutUnsafe(*os_, 'u');\n                if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {\n                    PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]);\n                }\n                else {\n                    RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);\n                    // Surrogate pair\n                    unsigned s = codepoint - 0x010000;\n                    unsigned lead = (s >> 10) + 0xD800;\n                    unsigned trail = (s & 0x3FF) + 0xDC00;\n                    PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(lead      ) & 15]);\n                    PutUnsafe(*os_, '\\\\');\n                    PutUnsafe(*os_, 'u');\n                    PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]);\n                    PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                    \n                }\n            }\n            else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {\n                is.Take();\n                PutUnsafe(*os_, '\\\\');\n                PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));\n                if (escape[static_cast<unsigned char>(c)] == 'u') {\n                    PutUnsafe(*os_, '0');\n                    PutUnsafe(*os_, '0');\n                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);\n                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);\n                }\n            }\n            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? \n                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :\n                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))\n                return false;\n        }\n        PutUnsafe(*os_, '\\\"');\n        return true;\n    }\n\n    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {\n        return RAPIDJSON_LIKELY(is.Tell() < length);\n    }\n\n    bool WriteStartObject() { os_->Put('{'); return true; }\n    bool WriteEndObject()   { os_->Put('}'); return true; }\n    bool WriteStartArray()  { os_->Put('['); return true; }\n    bool WriteEndArray()    { os_->Put(']'); return true; }\n\n    bool WriteRawValue(const Ch* json, size_t length) {\n        PutReserve(*os_, length);\n        for (size_t i = 0; i < length; i++) {\n            RAPIDJSON_ASSERT(json[i] != '\\0');\n            PutUnsafe(*os_, json[i]);\n        }\n        return true;\n    }\n\n    void Prefix(Type type) {\n        (void)type;\n        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root\n            Level* level = level_stack_.template Top<Level>();\n            if (level->valueCount > 0) {\n                if (level->inArray) \n                    os_->Put(','); // add comma if it is not the first element in array\n                else  // in object\n                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');\n            }\n            if (!level->inArray && level->valueCount % 2 == 0)\n                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name\n            level->valueCount++;\n        }\n        else {\n            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.\n            hasRoot_ = true;\n        }\n    }\n\n    // Flush the value if it is the top level one.\n    bool EndValue(bool ret) {\n        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text\n            os_->Flush();\n        return ret;\n    }\n\n    OutputStream* os_;\n    internal::Stack<StackAllocator> level_stack_;\n    int maxDecimalPlaces_;\n    bool hasRoot_;\n\nprivate:\n    // Prohibit copy constructor & assignment operator.\n    Writer(const Writer&);\n    Writer& operator=(const Writer&);\n};\n\n// Full specialization for StringStream to prevent memory copying\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt(int i) {\n    char *buffer = os_->Push(11);\n    const char* end = internal::i32toa(i, buffer);\n    os_->Pop(static_cast<size_t>(11 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint(unsigned u) {\n    char *buffer = os_->Push(10);\n    const char* end = internal::u32toa(u, buffer);\n    os_->Pop(static_cast<size_t>(10 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {\n    char *buffer = os_->Push(21);\n    const char* end = internal::i64toa(i64, buffer);\n    os_->Pop(static_cast<size_t>(21 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {\n    char *buffer = os_->Push(20);\n    const char* end = internal::u64toa(u, buffer);\n    os_->Pop(static_cast<size_t>(20 - (end - buffer)));\n    return true;\n}\n\ntemplate<>\ninline bool Writer<StringBuffer>::WriteDouble(double d) {\n    if (internal::Double(d).IsNanOrInf()) {\n        // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).\n        if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))\n            return false;\n        if (internal::Double(d).IsNan()) {\n            PutReserve(*os_, 3);\n            PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');\n            return true;\n        }\n        if (internal::Double(d).Sign()) {\n            PutReserve(*os_, 9);\n            PutUnsafe(*os_, '-');\n        }\n        else\n            PutReserve(*os_, 8);\n        PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');\n        PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');\n        return true;\n    }\n    \n    char *buffer = os_->Push(25);\n    char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);\n    os_->Pop(static_cast<size_t>(25 - (end - buffer)));\n    return true;\n}\n\n#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\ntemplate<>\ninline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {\n    if (length < 16)\n        return RAPIDJSON_LIKELY(is.Tell() < length);\n\n    if (!RAPIDJSON_LIKELY(is.Tell() < length))\n        return false;\n\n    const char* p = is.src_;\n    const char* end = is.head_ + length;\n    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));\n    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));\n    if (nextAligned > end)\n        return true;\n\n    while (p != nextAligned)\n        if (*p < 0x20 || *p == '\\\"' || *p == '\\\\') {\n            is.src_ = p;\n            return RAPIDJSON_LIKELY(is.Tell() < length);\n        }\n        else\n            os_->PutUnsafe(*p++);\n\n    // The rest of string using SIMD\n    static const char dquote[16] = { '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"', '\\\"' };\n    static const char bslash[16] = { '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\', '\\\\' };\n    static const char space[16]  = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };\n    const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));\n    const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));\n    const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));\n\n    for (; p != endAligned; p += 16) {\n        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));\n        const __m128i t1 = _mm_cmpeq_epi8(s, dq);\n        const __m128i t2 = _mm_cmpeq_epi8(s, bs);\n        const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19\n        const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);\n        unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));\n        if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped\n            SizeType len;\n#ifdef _MSC_VER         // Find the index of first escaped\n            unsigned long offset;\n            _BitScanForward(&offset, r);\n            len = offset;\n#else\n            len = static_cast<SizeType>(__builtin_ffs(r) - 1);\n#endif\n            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));\n            for (size_t i = 0; i < len; i++)\n                q[i] = p[i];\n\n            p += len;\n            break;\n        }\n        _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);\n    }\n\n    is.src_ = p;\n    return RAPIDJSON_LIKELY(is.Tell() < length);\n}\n#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)\n\nRAPIDJSON_NAMESPACE_END\n\n#ifdef _MSC_VER\nRAPIDJSON_DIAG_POP\n#endif\n\n#ifdef __clang__\nRAPIDJSON_DIAG_POP\n#endif\n\n#endif // RAPIDJSON_RAPIDJSON_H_\n"
  },
  {
    "path": "src/thread_data_base.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_THREAD_DATA_BASE_H\n#define DMKIT_THREAD_DATA_BASE_H\n\n#include <string>\n#include <vector>\n\nnamespace dmkit {\n\nclass ThreadDataBase {\npublic:\n    ThreadDataBase() {}\n    \n    virtual ~ThreadDataBase() {}\n    \n    virtual void reset() {\n        this->_log_id.clear();\n        this->_notice_log.clear();\n    }\n    \n    // Set a logid for current request, this logid will show in all logs for current request\n    void set_log_id(const std::string& log_id) { this->_log_id = log_id; }\n    \n    const std::string get_log_id() { return this->_log_id; }\n\n    // Add and save notice log inside thread data so that each request will log only one notice log\n    void add_notice_log(const std::string& key, const std::string& value) {\n        std::string log;\n        log += key;\n        log += \"=\";\n        log += value;\n        this->_notice_log.push_back(log);\n    }\n\n    // Get notice log as a string in the format \"key1=value1 key2=value2\"\n    const std::string get_notice_log() {\n        std::string log_str;\n        for (auto v: this->_notice_log) {\n            log_str += v;\n            log_str += \" \";\n        }\n        return log_str;\n    }\n\nprivate:\n    std::string _log_id;\n    std::vector<std::string> _notice_log;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_THREAD_DATA_BASE_H\n"
  },
  {
    "path": "src/token_manager.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"token_manager.h\"\n#include \"file_watcher.h\"\n#include \"rapidjson.h\"\n\nnamespace dmkit {\n\nTokenManager::TokenManager() {\n    this->_token_cache = new std::unordered_map<std::string, TokenValue>();\n}\n\nTokenManager::~TokenManager() {\n    delete this->_token_cache;\n    this->_token_cache = nullptr;\n    FileWatcher::get_instance().unregister_file(this->_client_key_conf_path);\n    this->_p_client_key_map.reset();\n}\n\nint TokenManager::init(const char* dir_path, const char* conf_file) {\n    std::string file_path;\n    if (dir_path != nullptr) {\n        file_path += dir_path;\n    }\n    if (!file_path.empty() && file_path[file_path.length() - 1] != '/') {\n        file_path += '/';\n    }\n    if (conf_file != nullptr) {\n        file_path += conf_file;\n    }\n\n    this->_client_key_conf_path = file_path;\n\n    ClientKeyMap* client_key_map = this->load_client_key_map();\n    if (client_key_map == nullptr) {\n        APP_LOG(ERROR) << \"Failed to init TokenManager, cannot load client key map\";\n        return -1;\n    }\n\n    this->_p_client_key_map.reset(client_key_map);\n    FileWatcher::get_instance().register_file(\n        this->_client_key_conf_path, TokenManager::client_key_conf_change_callback, this, true);\n\n    return 0;\n}\n\nint TokenManager::reload() {\n    APP_LOG(TRACE) << \"Reloading TokenManager...\";\n    ClientKeyMap* client_key_map = this->load_client_key_map();\n    if (client_key_map == nullptr) {\n        APP_LOG(ERROR) << \"Failed to reload TokenManager, cannot load client key map\";\n        return -1;\n    }\n\n    this->_p_client_key_map.reset(client_key_map);\n    std::lock_guard<std::mutex> lock(this->_token_cache_mutex);\n    this->_token_cache->clear();\n    APP_LOG(TRACE) << \"Reload finished.\";\n    return 0;\n}\n\nint TokenManager::client_key_conf_change_callback(void* param) {\n    TokenManager* tm = (TokenManager*)param;\n    return tm->reload();\n}\n\nint TokenManager::get_access_token(const std::string bot_id,\n                                   const RemoteServiceManager* remote_service_manager,\n                                   std::string& access_token) {\n    TokenValue token_value;\n    if (this->get_token_from_cache(bot_id, token_value) == 0) {\n        access_token = token_value.access_token;\n        return 0;\n    }\n    std::shared_ptr<ClientKeyMap> p_client_key_map(this->_p_client_key_map);\n    auto client_key_iter = p_client_key_map->find(bot_id);\n    if (client_key_iter == p_client_key_map->end()) {\n        return -1;\n    }\n    ClientKey client_key = client_key_iter->second;\n    if (this->get_token_from_remote(client_key, remote_service_manager, token_value) != 0) {\n        return -1;\n    }\n    this->update_token_cache(bot_id, token_value);\n    access_token = token_value.access_token;\n    return 0;\n}\n\nClientKeyMap* TokenManager::load_client_key_map() {\n    FILE* fp = fopen(this->_client_key_conf_path.c_str(), \"r\");\n    if (fp == nullptr) {\n        APP_LOG(ERROR) << \"Failed to open file \" << this->_client_key_conf_path;\n        return nullptr;\n    }\n\n    char read_buffer[1024];\n    rapidjson::FileReadStream is(fp, read_buffer, sizeof(read_buffer));\n    rapidjson::Document doc;\n    doc.ParseStream(is);\n    fclose(fp);\n    if (doc.HasParseError() || !doc.IsObject()) {\n        APP_LOG(ERROR) << \"Failed to parse Token settings\";\n        return nullptr;\n    }\n\n    ClientKeyMap* client_key_map = new ClientKeyMap();\n    for (rapidjson::Value::ConstMemberIterator bot_iter = doc.MemberBegin();\n         bot_iter != doc.MemberEnd(); ++bot_iter) {\n        std::string bot_id = bot_iter->name.GetString();\n        if (!bot_iter->value.IsObject()) {\n            APP_LOG(ERROR) << \"Invalid token conf for \" << bot_id << \", invalid format\";\n            delete client_key_map;\n            return nullptr;\n        }\n        const rapidjson::Value& val_token = bot_iter->value;\n        if (!val_token.HasMember(\"api_key\") || !val_token[\"api_key\"].IsString()) {\n            APP_LOG(ERROR) << \"Invalid token conf for \" << bot_id << \", missing api_key\";\n            delete client_key_map;\n            return nullptr;\n        }\n        if (!val_token.HasMember(\"secret_key\") || !val_token[\"secret_key\"].IsString()) {\n            APP_LOG(ERROR) << \"Invalid token conf for \" << bot_id << \", missing secret_key\";\n            delete client_key_map;\n            return nullptr;\n        }\n        ClientKey client_key;\n        client_key.api_key = val_token[\"api_key\"].GetString();\n        client_key.secret_key = val_token[\"secret_key\"].GetString();\n        (*client_key_map)[bot_id] = client_key;\n    }\n\n    return client_key_map;\n}\n\nint TokenManager::get_token_from_cache(const std::string bot_id, TokenValue& token_value) {\n    time_t expire_guard = time(nullptr) + 60;\n    std::lock_guard<std::mutex> lock(this->_token_cache_mutex);\n    auto token_iter = this->_token_cache->find(bot_id);\n    if (token_iter == this->_token_cache->end()) {\n        return -1;\n    }\n    TokenValue value = token_iter->second;\n    if (value.expire_time < expire_guard) {\n        return -1;\n    }\n    token_value = value;\n    return 0;\n}\n\nint TokenManager::update_token_cache(const std::string bot_id, const TokenValue token_value) {\n    std::lock_guard<std::mutex> lock(this->_token_cache_mutex);\n    (*this->_token_cache)[bot_id] = token_value;\n    return 0;\n}\n\nint TokenManager::get_token_from_remote(const ClientKey client_key,\n        const RemoteServiceManager* remote_service_manager, TokenValue& token_value) {\n    std::string url = \"/oauth/2.0/token?grant_type=client_credentials\";\n    url += \"&client_id=\" + client_key.api_key + \"&client_secret=\" + client_key.secret_key;\n    RemoteServiceParam rsp = {\n        url,\n        HTTP_METHOD_GET,\n        \"\"\n    };\n    RemoteServiceResult rsr;\n    if (remote_service_manager->call(\"token_auth\", rsp, rsr) != 0) {\n        APP_LOG(ERROR) << \"Failed to get authorization result\";\n        return -1;\n    }\n    rapidjson::Document json;\n    if (json.Parse(rsr.result.c_str()).HasParseError()) {\n        APP_LOG(ERROR) << \"Failed to parse authorization result to json\";\n        return -1;\n    }\n    token_value.access_token = json[\"access_token\"].GetString();\n    token_value.expire_time = time(0) + json[\"expires_in\"].GetInt();\n    return 0;\n}\n\n} //namespace dmkit\n"
  },
  {
    "path": "src/token_manager.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include <ctime>\n#include <memory>\n#include <mutex>\n#include <unordered_map>\n#include \"app_log.h\"\n#include \"remote_service_manager.h\"\n\n#ifndef DMKIT_TOKEN_MANAGER_H\n#define DMKIT_TOKEN_MANAGER_H\n\nnamespace dmkit {\n\nstruct ClientKey {\n    std::string api_key;\n    std::string secret_key;\n};\n\nstruct TokenValue {\n    // access token\n    std::string access_token;\n    // timestamp when the access token expires\n    std::time_t expire_time;\n\n};\n\n// Type for client key map.\ntypedef std::unordered_map<std::string, ClientKey> ClientKeyMap;\n\n// A Manager class to manage and cache access token accessing unit bot api.\nclass TokenManager {\npublic:\n    TokenManager();\n\n    ~TokenManager();\n\n    // Initialization with a json configuration file.\n    int init(const char* dir_path, const char* conf_file);\n\n    // Reload config.\n    int reload();\n\n    // Callback when conf change.\n    static int client_key_conf_change_callback(void* param);\n\n    // Get access token with bot id.\n    int get_access_token(const std::string bot_id,\n            const RemoteServiceManager* remote_service_manager, std::string& access_token);\n\nprivate:\n    int get_token_from_cache(const std::string bot_id, TokenValue& token_value);\n    int update_token_cache(const std::string bot_id, const TokenValue token_value);\n\n    int get_token_from_remote(const ClientKey client_key,\n            const RemoteServiceManager* remote_service_manager, TokenValue& token_value);\n\n    ClientKeyMap* load_client_key_map();\n\n    std::string _client_key_conf_path;\n    std::shared_ptr<ClientKeyMap> _p_client_key_map;\n\n    std::unordered_map<std::string, TokenValue>* _token_cache;\n    std::mutex _token_cache_mutex;\n};\n\n}\n\n#endif\n\n"
  },
  {
    "path": "src/user_function/demo.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"demo.h\"\n#include \"../utils.h\"\n\nnamespace dmkit {\nnamespace user_function {\nnamespace demo {\n\n// These functions are for demo purpose which returns mock data.\n// In real application, these might need to invoke a remote service call.\n// Http GET/POST calls are already included as shared function.\n\nint get_cellular_data_usage(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n\n    std::vector<std::string> elements;\n    utils::split(args[0], '-', elements);\n    if (elements.size() > 1 && elements[1] == \"01\") {\n        result = \"0\";\n    } else {\n        result = \"2\";\n    }\n    \n    return 0;\n}\n\nint get_cellular_data_left(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n\n    std::vector<std::string> elements;\n    utils::split(args[0], '-', elements);\n    if (elements.size() > 1 && elements[1] == \"01\") {\n        result = \"2\";\n    } else {\n        result = \"0\";\n    }\n    \n    return 0;\n}\n\nint get_package_options(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n\n    if (args[0] == \"省内流量包\") {\n        result = \"10元100M，20元300M\";\n    } else if (args[0] == \"全国流量包\") {\n        result = \"10元100M，50元1G\";\n    } else {\n        result = \"20元300M，50元1G\";\n    }\n\n    return 0;\n}\n\n} // namespace demo\n} // namespace user_function\n} // namespace dmkit\n"
  },
  {
    "path": "src/user_function/demo.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_USER_FUNCTION_DEMO_H\n#define DMKIT_USER_FUNCTION_DEMO_H\n\n#include <string>\n#include <vector>\n#include \"../request_context.h\"\n\nnamespace dmkit {\nnamespace user_function {\nnamespace demo {\n\n// Functions used in our demo scenario\nint get_cellular_data_usage(const std::vector<std::string>& args,\n                            const RequestContext& context,\n                            std::string& result);\n\nint get_cellular_data_left(const std::vector<std::string>& args,\n                            const RequestContext& context,\n                            std::string& result);\n\nint get_package_options(const std::vector<std::string>& args,\n                            const RequestContext& context,\n                            std::string& result);\n\n} // namespace demo\n} // namespace user_function\n} // namespace dmkit\n\n#endif  //DMKIT_USER_FUNCTION_DEMO_H\n\n"
  },
  {
    "path": "src/user_function/shared.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include \"shared.h\"\n#include <ctime>\n#include <curl/curl.h>\n#include <iostream>\n#include <math.h>\n#include <sstream>\n#include <stdlib.h>\n#include <time.h>\n#include <unordered_map>\n#include \"../app_log.h\"\n#include \"../rapidjson.h\"\n#include \"../utils.h\"\n\nnamespace dmkit {\nnamespace user_function {\n\n// All user functions share the same signature,\n// arg:\n//    args: arguements supplied in configuration\n//    context: current request context\n//    result: value assigned to parameter value in configuration\n// return: \n//    0 if function process success\n//    -1 if function process fail\n\n// Get value from a JSON string with supplied path.\n// args[0]: JSON string\n// args[1]: path to search for, split with a dot sign\nint json_get_value(const std::vector<std::string>& args,\n                   const RequestContext& context,\n                   std::string& result) {\n    (void)context;\n    result = \"\";\n    if (args.size() < 2) {\n        return -1;\n    }\n\n    std::string data = args[0];\n    std::string search = args[1];\n    if (search.empty()) {\n        return -1;\n    }\n    rapidjson::Document doc;\n    if (doc.Parse(data.c_str()).HasParseError() || (!doc.IsObject() && !doc.IsArray())) {\n        APP_LOG(WARNING) << \"Failed to load json data: \" << data;\n        return -1;\n    }\n    std::size_t last_pos = 0;\n    const rapidjson::Value* value = &doc;\n    while (last_pos < search.length()) {\n        std::size_t pos = search.find('.', last_pos);\n        if (pos == std::string::npos) {\n            pos = search.length();\n        }\n        std::string key = search.substr(last_pos, pos - last_pos);\n        last_pos = pos + 1;\n\n        utils::trim(key);\n        if (key.empty()) {\n            return -1;\n        }\n\n        if (value->IsObject()) {\n            const rapidjson::Value::ConstMemberIterator miter = value->FindMember(key.c_str());\n            if (miter == value->MemberEnd()) {\n                return -1;\n            }\n            value = &(miter->value);\n            continue;\n        } else if (value->IsArray()) {\n            if (key.empty()) {\n                return -1;\n            }\n            unsigned index = atoi(key.c_str());\n            if (index == 0 && key[0] != '0') {\n                return -1;\n            }\n            if (value->Size() <= index) {\n                return -1;\n            }\n            value = &((*value)[index]);\n        } else {\n            return -1;\n        }\n    }\n\n    if (value->IsNull()) {\n        return -1;\n    }\n\n    if (value->IsUint()) {\n        unsigned num = value->GetUint();\n        result = std::to_string(num);\n    } else if (value->IsInt()) {\n        int num = value->GetInt();\n        result = std::to_string(num);\n    } else if (value->IsUint64()) {\n        unsigned long num = value->GetUint64();\n        result = std::to_string(num);\n    } else if (value->IsInt64()) {\n        long num = value->GetInt64();\n        result = std::to_string(num);\n    } else if (value->IsDouble()) {\n        double num = value->GetDouble();\n        result = std::to_string(num);\n    } else if (value->IsString()) {\n        result = value->GetString();\n    } else {\n        rapidjson::StringBuffer buffer;\n        rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n        value->Accept(writer);\n        result = buffer.GetString();\n    }\n\n    return 0;\n}\n\n// String replacement.\n// args[0]: string\n// args[1]: sub string to be replaced\n// args[2]: a new string to replace with\nint replace(const std::vector<std::string>& args,\n            const RequestContext& context, std::string& result) {\n    (void)context;\n    if (args.size() != 3) {\n        return -1;\n    }\n    std::string str = args[0];\n    std::string old_substr = args[1];\n    std::string new_substr = args[2];\n    size_t pos = str.find(old_substr);\n    if (pos != std::string::npos) {\n        str.replace(pos, old_substr.length(), new_substr);\n    }\n\n    result = str;\n    return 0;\n}\n\n// split string with delimiter and choose one element from resulting list\n// args[0]: string\n// args[1]: delimeter to split\n// args[2]: \"random\" to choose randomly or a number indicate the index to choose \nint split_and_choose(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    (void)context;\n    if (args.size() != 3) {\n        return -1;\n    }\n    std::string str = args[0];\n    std::string delimiter = args[1];\n    std::string choose = args[2];\n    std::vector<std::string> elements;\n    if (delimiter.length() != 1) {\n        APP_LOG(WARNING) << \"Delimiter only support one character\";\n        return -1;\n    }\n    \n    ::dmkit::utils::split(str, delimiter[0], elements);\n    if (elements.empty()) {\n        return -1;\n    }\n    int size = elements.size();\n    int index = 0;\n    if (choose == \"random\") {\n        index = std::time(nullptr) % size;\n    } else if (!::dmkit::utils::try_atoi(choose, index) || index >= size) {\n            return -1;\n    }\n    result = elements[index];\n    return 0;\n}\n\n\n// Add all integer numbers supplied in args.\nint number_add(const std::vector<std::string>& args,\n               const RequestContext& context,\n               std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n    long res = 0;\n    for (auto & arg : args) {\n        if (arg.empty()) {\n            return -1;\n        }\n        int num = atoi(arg.c_str());\n        if (num == 0 && arg[0] != '0') {\n            return -1;\n        }\n        res += num;\n    }\n\n    result = std::to_string(res);\n    return 0;\n}\n\n// Multiply all float numbers supplied in args.\nint float_mul(const std::vector<std::string>& args,\n               const RequestContext& context,\n               std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n    double res = 1;\n    for (auto & arg : args) {\n        if (arg.empty()) {\n            return -1;\n        }\n        double num = atof(arg.c_str());\n        const double EPSILON = 1e-9;\n        if (fabs(num) < EPSILON && arg[0] != '0') {\n            return -1;\n        }\n        res *= num;\n    }\n\n    result = std::to_string(res);\n    return 0;\n}\n\n// Return args[2] if args[0] equals to args[1],\n// otherwise return args[3]\nint choose_if_equal(const std::vector<std::string>& args,\n                    const RequestContext& context,\n                    std::string& result) {\n    (void)context;\n    if (args.size() < 4) {\n        return -1;\n    }\n    if (args[0] == args[1]) {\n        result = args[2];\n        return 0;\n    }\n\n    result = args[3];\n    return 0;\n}\n\n// Url encode args[0]\nint url_encode(const std::vector<std::string>& args,\n               const RequestContext& context,\n               std::string& result) {\n    (void)context;\n    if (args.size() < 1) {\n        return -1;\n    }\n\n    if (args[0].empty()) {\n        result = \"\";\n        return 0;\n    }\n\n    CURL *curl = curl_easy_init();\n    if (!curl) {\n        return -1;\n    }\n    char *output = curl_easy_escape(curl, args[0].c_str(), args[0].length());\n    if (!output) {\n        curl_easy_cleanup(curl);\n        return -1;\n    }\n    result.assign(output);\n    curl_free(output);\n    curl_easy_cleanup(curl);\n\n    return 0;\n}\n\n// Make a http get request.\n// args[0]: service name\n// args[1]: url\nint service_http_get(const std::vector<std::string>& args,\n                      const RequestContext& context,\n                    std::string& result) {\n    if (args.size() < 2) {\n        return -1;\n    }\n\n    const RemoteServiceManager* rsm = context.remote_service_manager();\n    RemoteServiceParam rsm_param = {\n        args[1],\n        HTTP_METHOD_GET,\n        \"\",\n    };\n    RemoteServiceResult rsm_result;\n    if (rsm->call(args[0], rsm_param, rsm_result) != 0) {\n        return -1;\n    }\n\n    result = rsm_result.result;\n    return 0;\n}\n\n// Make a http post request.\n// args[0]: service name\n// args[1]: url\n// args[2], ...: these arguments will be concatenated and used as the http post body.\nint service_http_post(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    if (args.size() < 2) {\n        return -1;\n    }\n\n    const RemoteServiceManager* rsm = context.remote_service_manager();\n    std::string post_data = \"\";\n    for (size_t i = 2; i < args.size(); i++) {\n        if (i == 2) {\n            post_data = args[i];\n        } else {\n            post_data = post_data + \",\" + args[i];\n        }\n    }\n    APP_LOG(TRACE) << \"post data request:\" << post_data;\n    RemoteServiceParam rsm_param = {\n        args[1],\n        HTTP_METHOD_POST,\n        post_data,\n    };\n    RemoteServiceResult rsm_result;\n    if (rsm->call(args[0], rsm_param, rsm_result) != 0) {\n        return -1;\n    }\n\n    result = rsm_result.result;\n    APP_LOG(TRACE) << \"post data result:\" << result;\n    return 0;\n}\n\n// Get strftime result for current time\n// args[0]: strftime used format string\nint now_strftime(const std::vector<std::string>& args,\n        const RequestContext& context, std::string& result) {\n    (void)context;\n    \n    if (args.size() < 1) {\n        return -1;\n    }\n    time_t t = time(0);\n    struct tm now;\n    localtime_r(&t, &now);\n    char buffer [80];\n    if (strftime(buffer, 80, args[0].c_str(), &now) == 0) {\n        APP_LOG(WARNING) << \"strftime returns 0!\";\n        return -1;\n    }\n\n    result = buffer;\n    return 0;\n}\n\n} // namespace user_function\n} // namespace dmkit\n\n"
  },
  {
    "path": "src/user_function/shared.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_USER_FUNCTION_SHARED_H\n#define DMKIT_USER_FUNCTION_SHARED_H\n\n#include <string>\n#include <vector>\n#include \"../request_context.h\"\n\nnamespace dmkit {\nnamespace user_function {\n\n// JSON Operations\nint json_get_value(const std::vector<std::string>& args,\n                   const RequestContext& context,\n                   std::string& result);\n\n// String Operations\nint replace(const std::vector<std::string>& args,\n            const RequestContext& context,\n            std::string& result);\n\nint split_and_choose(const std::vector<std::string>& args,\n                     const RequestContext& context,\n                     std::string& result);\n\n// Arithmetic Operations\nint number_add(const std::vector<std::string>& args,\n               const RequestContext& context,\n               std::string& result);\n\nint float_mul(const std::vector<std::string>& args,\n              const RequestContext& context,\n              std::string& result);\n\n// Logical Operations\nint choose_if_equal(const std::vector<std::string>& args,\n                    const RequestContext& context,\n                    std::string& result);\n\n// Network Operations\nint url_encode(const std::vector<std::string>& args,\n               const RequestContext& context,\n               std::string& result);\n\nint service_http_get(const std::vector<std::string>& args,\n                     const RequestContext& context,\n                     std::string& result);\n\nint service_http_post(const std::vector<std::string>& args,\n                      const RequestContext& context,\n                      std::string& result);\n\n// Time Related\nint now_strftime(const std::vector<std::string>& args,\n                 const RequestContext& context,\n                 std::string& result);\n\n} // namespace user_function\n} // namespace dmkit\n\n#endif  //DMKIT_USER_FUNCTION_SHARED_H\n\n"
  },
  {
    "path": "src/user_function_manager.cpp",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#include <curl/curl.h>\n#include \"app_log.h\"\n#include \"user_function_manager.h\"\n#include \"user_function/shared.h\"\n#include \"user_function/demo.h\"\n\nnamespace dmkit {\n\nUserFunctionManager::UserFunctionManager() {\n    this->_user_function_map = new std::unordered_map<std::string, UserFunctionPtr>();\n    this->_init = false;\n}\n\nUserFunctionManager::~UserFunctionManager() {\n    delete this->_user_function_map;\n    this->_user_function_map = nullptr;\n    \n    if (this->_init) {\n        curl_global_cleanup();\n        this->_init = false;\n    }\n}\n\nint UserFunctionManager::init() {\n    // All user functions should be registered here.\n    // Shared functions.\n    (*_user_function_map)[\"json_get_value\"] = user_function::json_get_value;\n    (*_user_function_map)[\"replace\"] = user_function::replace;\n    (*_user_function_map)[\"split_and_choose\"] = user_function::split_and_choose;\n    (*_user_function_map)[\"number_add\"] = user_function::number_add;\n    (*_user_function_map)[\"float_mul\"] = user_function::float_mul;\n    (*_user_function_map)[\"choose_if_equal\"] = user_function::choose_if_equal;\n    (*_user_function_map)[\"url_encode\"] = user_function::url_encode;\n    (*_user_function_map)[\"service_http_get\"] = user_function::service_http_get;\n    (*_user_function_map)[\"service_http_post\"] = user_function::service_http_post;\n    (*_user_function_map)[\"now_strftime\"] = user_function::now_strftime;\n\n    // Scenario specific functions.\n    (*_user_function_map)[\"demo_get_cellular_data_usage\"] = \n            user_function::demo::get_cellular_data_usage;\n    (*_user_function_map)[\"demo_get_cellular_data_left\"] = \n            user_function::demo::get_cellular_data_left;\n    (*_user_function_map)[\"demo_get_package_options\"] = user_function::demo::get_package_options;\n\n    // Curl init is required for url_encode function.\n    if (curl_global_init(CURL_GLOBAL_DEFAULT) != 0) {\n        APP_LOG(WARNING) << \"curl_global_init returns non-zeros\";\n        return -1;\n    }\n\n    this->_init = true;\n    return 0;\n}\n\nint UserFunctionManager::call_user_function(const std::string& func_name,\n                                            const std::vector<std::string>& args,\n                                            const RequestContext& context,\n                                            std::string& result) {\n    auto find_res = this->_user_function_map->find(func_name);\n    if (find_res == this->_user_function_map->end()) {\n        APP_LOG(WARNING) << \"call to undefined user function: \" << func_name;\n        return -1;\n    }\n    UserFunctionPtr func_ptr = find_res->second;\n    int res = -1;\n    try {\n        res = (*func_ptr)(args, context, result);\n    } catch (const char* msg) {\n        APP_LOG(WARNING) << \"Exception calling user function [\"\n            << func_name << \"], exception: \" << msg;\n        res = -1;\n    }\n\n    return res;\n}\n\n} // namespace dmkit\n"
  },
  {
    "path": "src/user_function_manager.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_USER_FUNCTION_MANAGER_H\n#define DMKIT_USER_FUNCTION_MANAGER_H\n\n#include <string>\n#include <unordered_map>\n#include <vector>\n#include \"request_context.h\"\n\nnamespace dmkit {\n\ntypedef int (*UserFunctionPtr)(const std::vector<std::string>& args,\n                               const RequestContext& context,\n                               std::string& result);\n\nclass UserFunctionManager {\npublic:\n    UserFunctionManager();\n    ~UserFunctionManager();\n\n    int init();\n    int call_user_function(const std::string& func_name,\n                           const std::vector<std::string>& args,\n                           const RequestContext& context,\n                           std::string& result);\n\nprivate:\n    std::unordered_map<std::string, UserFunctionPtr>* _user_function_map;\n    bool _init;\n};\n\n} // namespace dmkit\n\n#endif  //DMKIT_USER_FUNCTION_MANAGER_H\n"
  },
  {
    "path": "src/utils.h",
    "content": "// Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n// \n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// 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#ifndef DMKIT_UTILS_H\n#define DMKIT_UTILS_H\n\n#include <stdlib.h>\n#include <string>\n#include \"app_log.h\"\n#include \"rapidjson.h\"\n\nnamespace dmkit {\nnamespace utils {\n\nstatic inline void ltrim(std::string &s) {\n    s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](int ch) {\n        return !std::isspace(ch);\n    }));\n}\n\nstatic inline void rtrim(std::string &s) {\n    s.erase(std::find_if(s.rbegin(), s.rend(), [](int ch) {\n        return !std::isspace(ch);\n    }).base(), s.end());\n}\n\nstatic inline void trim(std::string &s) {\n    ltrim(s);\n    rtrim(s);\n}\n\nstatic inline bool try_atoi(const std::string& str, int& value) {\n    if (str.empty()) {\n        return false;\n    }\n\n    value = atoi(str.c_str());\n    if (value == 0 && str[0] != '0') {\n        return false;\n    }\n\n    if (value < 0 && str[0] != '-') {\n        return false;\n    }\n\n    return true;\n}\n\nstatic inline bool try_atof(const std::string& str, double& value) {\n    if (str.empty()) {\n        return false;\n    }\n\n    value = atof(str.c_str());\n    const double EPSILON = 1e-9;\n    if (fabs(value) < EPSILON && str[0] != '0') {\n        return false;\n    }\n\n    return true;\n}\n\nstatic inline bool split(const std::string& str, const char sep, std::vector<std::string>& elems) {\n    elems.clear();\n    if (str.empty()) {\n        return false;\n    }\n    std::istringstream ss(str);\n    std::string item;\n    while (std::getline(ss, item, sep)) {\n        elems.push_back(item);\n    } \n    return true;\n}\n\nstatic inline std::string json_to_string(const rapidjson::Value& value) {\n    rapidjson::StringBuffer buffer;\n    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);\n    value.Accept(writer);\n    return buffer.GetString();\n}\n\n} // namespace utils\n} // namespace dmkit\n\n#endif  //DMKIT_UTILS_H\n"
  },
  {
    "path": "tools/bot_emulator.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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\"\"\"\nA simple console program to emulate a bot for user to interact with\n\n\"\"\"\n\nimport json\nimport os\nimport random\nimport requests\nimport sys\n\n\ndef main(bot_id, token):\n    \"\"\"\n    Bot emulator\n    Read user input and get bot response\n\n    \"\"\"\n    # Url of dmkit, change this if you are runnning dmkit in a different ip/port.\n    url = \"http://127.0.0.1:8010/search?access_token=\" + token\n    \n    json_header = {'Content-Type': 'application/json'}\n    user_id = str(random.randint(1, 100000))\n    session = \"\"\n    while True:\n        print \"-----------------------------------------------------------------\"\n        user_input = raw_input(\"input:\\n\")\n        user_input = user_input.strip()\n        if not user_input:\n            continue\n        logid = str(random.randint(100000,999999))\n        payload = {\n            \"version\": \"2.0\",\n            \"bot_id\": bot_id,\n            \"log_id\": logid,\n            \"request\": {\n                \"user_id\": user_id,\n                \"query\": user_input,\n                \"query_info\": {\n                    \"type\": \"TEXT\",\n                    \"source\": \"ASR\",\n                    \"asr_candidates\": []\n                },\n                \"updates\": \"\",\n                \"client_session\": \"{\\\"client_results\\\":\\\"\\\", \\\"candidate_options\\\":[]}\",\n                \"bernard_level\": 1\n            },\n            \"bot_session\": session\n        }\n        obj = requests.post(url, data=json.dumps(payload), headers=json_header).json()\n        print \"BOT:\"\n        # Not a valid response.\n        if obj['error_code'] != 0:\n            print \"ERROR: %s\" % obj['error_msg']\n            continue\n        \n        session = obj['result']['bot_session']\n        response = obj['result']['response']\n        action = response['action_list'][0]\n        # For clarify or failed responses which dmkit does not take actions.\n        if action['type'] != 'event':\n            print action['say']\n            continue\n        \n        custom_reply = json.loads(action['custom_reply'])\n        if custom_reply['event_name'] != 'DM_RESULT':\n            print 'ERROR:unknown event name %s' % custom_reply['event_name']\n            continue\n        # This is a dmkit response\n        dm_result = json.loads(custom_reply['result'])\n        for item in dm_result['result']:\n            if item['type'] == 'tts':\n                print item['value']\n\n\nif __name__ == \"__main__\":\n    if len(sys.argv) < 2:\n        print \"Usage: %s %s %s\" % (sys.argv[0], \"[bot_id]\", \"[access_token]\")\n    else:\n        main(sys.argv[1], sys.argv[2])\n"
  },
  {
    "path": "tools/mock_api_server.py",
    "content": "# -*- coding: utf-8 -*-\n#\n# Copyright (c) 2018 Baidu, Inc. All Rights Reserved.\n# \n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# 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\"\"\"\nA mock server to provide api which DMKit can access to retrieve resources\n\n\"\"\"\n\nfrom flask import Flask\nfrom flask import request\napp = Flask(__name__)\n\n@app.route(\"/hotel/search\")\ndef hotel_search():\n    location = request.args.get('location')\n    return \"如家酒店、四季酒店和香格里拉酒店\"\n\n@app.route(\"/hotel/book\")\ndef hotel_book():\n    time = request.args.get('time')\n    hotel = request.args.get('hotel')\n    room_type = request.args.get('room_type')\n    return \"OK\"\n\n"
  }
]